aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Readme.html1
-rw-r--r--src/main/javassist/CtBehavior.java78
-rw-r--r--src/main/javassist/bytecode/CodeAttribute.java7
-rw-r--r--src/main/javassist/bytecode/CodeIterator.java21
-rw-r--r--src/main/javassist/bytecode/LineNumberAttribute.java60
-rw-r--r--src/main/javassist/bytecode/LocalVariableAttribute.java16
6 files changed, 175 insertions, 8 deletions
diff --git a/Readme.html b/Readme.html
index c4632214..5e0d527a 100644
--- a/Readme.html
+++ b/Readme.html
@@ -259,6 +259,7 @@ see javassist.Dump.
<li>javassist.bytecode.DeprecatedAttribute has been added.
<li>javassist.bytecode.LocalVariableAttribute has been added.
<li>CtClass.getURL() and javassist.ClassPath.find() has been added.
+ <li>CtBehavior.insertAt() has been added.
</ul>
<p>- version 2.6 in August, 2003.
diff --git a/src/main/javassist/CtBehavior.java b/src/main/javassist/CtBehavior.java
index 636a8105..7824dbe1 100644
--- a/src/main/javassist/CtBehavior.java
+++ b/src/main/javassist/CtBehavior.java
@@ -672,4 +672,82 @@ public abstract class CtBehavior extends CtMember {
throw new CannotCompileException(e);
}
}
+
+ /**
+ * Inserts bytecode at the specified line in the body. It is equivalent
+ * to insertAt(lineNum, true, src).
+ *
+ * @param lineNum the line number.
+ * @param src the source code representing the inserted bytecode.
+ * It must be a single statement or block.
+ */
+ public int insertAt(int lineNum, String src)
+ throws CannotCompileException
+ {
+ return insertAt(lineNum, true, src);
+ }
+
+ /**
+ * Inserts bytecode at the specified line in the body.
+ *
+ * @param lineNum the line number.
+ * @param modify if false, this method does not insert the bytecode.
+ * It instead only returns the line number at which
+ * the bytecode would be inserted.
+ * @param src the source code representing the inserted bytecode.
+ * It must be a single statement or block.
+ * If modify is false, the value of src can be null.
+ */
+ public int insertAt(int lineNum, boolean modify, String src)
+ throws CannotCompileException
+ {
+ CodeAttribute ca = methodInfo.getCodeAttribute();
+ if (ca == null)
+ throw new CannotCompileException("no method body");
+
+ LineNumberAttribute ainfo
+ = (LineNumberAttribute)ca.getAttribute(LineNumberAttribute.tag);
+ if (ainfo == null)
+ throw new CannotCompileException("no line number info");
+
+ LineNumberAttribute.Pc pc = ainfo.toNearPc(lineNum);
+ lineNum = pc.line;
+ int index = pc.index;
+ if (!modify)
+ return lineNum;
+
+ declaringClass.checkModify();
+ CodeIterator iterator = ca.iterator();
+ Javac jv = new Javac(declaringClass);
+ try {
+ jv.recordParams(getParameterTypes(),
+ Modifier.isStatic(getModifiers()));
+ jv.compileStmnt(src);
+ Bytecode b = jv.getBytecode();
+ int stack = b.getMaxStack();
+ int locals = b.getMaxLocals();
+
+ /* We assume that there is no values in the operand stack
+ * at the position where the bytecode is inserted.
+ */
+ if (stack > ca.getMaxStack())
+ ca.setMaxStack(stack);
+
+ if (locals > ca.getMaxLocals())
+ ca.setMaxLocals(locals);
+
+ iterator.insert(index, b.get());
+ iterator.insert(b.getExceptionTable(), index);
+ return lineNum;
+ }
+ catch (NotFoundException e) {
+ throw new CannotCompileException(e);
+ }
+ catch (CompileError e) {
+ throw new CannotCompileException(e);
+ }
+ catch (BadBytecode e) {
+ throw new CannotCompileException(e);
+ }
+ }
}
diff --git a/src/main/javassist/bytecode/CodeAttribute.java b/src/main/javassist/bytecode/CodeAttribute.java
index b146440a..938d41e5 100644
--- a/src/main/javassist/bytecode/CodeAttribute.java
+++ b/src/main/javassist/bytecode/CodeAttribute.java
@@ -295,7 +295,7 @@ public class CodeAttribute extends AttributeInfo implements Opcode {
LdcEntry ldc = copyCode(this.info, 0, len, this.getConstPool(),
newCode, destCp, classnames);
- return LdcEntry.doit(newCode, ldc, etable);
+ return LdcEntry.doit(newCode, ldc, etable, this);
}
private static LdcEntry copyCode(byte[] code, int beginPos, int endPos,
@@ -377,12 +377,13 @@ final class LdcEntry {
int where;
int index;
- static byte[] doit(byte[] code, LdcEntry ldc, ExceptionTable etable)
+ static byte[] doit(byte[] code, LdcEntry ldc, ExceptionTable etable,
+ CodeAttribute ca)
throws BadBytecode
{
while (ldc != null) {
int where = ldc.where;
- code = CodeIterator.insertGap(code, where, 1, false, etable);
+ code = CodeIterator.insertGap(code, where, 1, false, etable, ca);
code[where] = (byte)Opcode.LDC_W;
ByteArray.write16bit(ldc.index, code, where + 1);
ldc = ldc.next;
diff --git a/src/main/javassist/bytecode/CodeIterator.java b/src/main/javassist/bytecode/CodeIterator.java
index 03c65da3..5c89bbad 100644
--- a/src/main/javassist/bytecode/CodeIterator.java
+++ b/src/main/javassist/bytecode/CodeIterator.java
@@ -450,7 +450,7 @@ public class CodeIterator implements Opcode {
int cur = currentPos;
byte[] c = insertGap(bytecode, pos, length, exclusive,
- get().getExceptionTable());
+ get().getExceptionTable(), codeAttr);
int length2 = c.length - bytecode.length;
if (cur >= pos)
currentPos = cur + length2;
@@ -599,19 +599,19 @@ public class CodeIterator implements Opcode {
* a multiple of 4.
*/
static byte[] insertGap(byte[] code, int where, int gapLength,
- boolean exclusive, ExceptionTable etable)
+ boolean exclusive, ExceptionTable etable, CodeAttribute ca)
throws BadBytecode
{
if (gapLength <= 0)
return code;
try {
- return insertGap0(code, where, gapLength, exclusive, etable);
+ return insertGap0(code, where, gapLength, exclusive, etable, ca);
}
catch (AlignmentException e) {
try {
return insertGap0(code, where, (gapLength + 3) & ~3,
- exclusive, etable);
+ exclusive, etable, ca);
}
catch (AlignmentException e2) {
throw new RuntimeException("fatal error?");
@@ -620,13 +620,24 @@ public class CodeIterator implements Opcode {
}
private static byte[] insertGap0(byte[] code, int where, int gapLength,
- boolean exclusive, ExceptionTable etable)
+ boolean exclusive, ExceptionTable etable,
+ CodeAttribute ca)
throws BadBytecode, AlignmentException
{
int codeLength = code.length;
byte[] newcode = new byte[codeLength + gapLength];
insertGap2(code, where, gapLength, codeLength, newcode, exclusive);
etable.shiftPc(where, gapLength, exclusive);
+ LineNumberAttribute na
+ = (LineNumberAttribute)ca.getAttribute(LineNumberAttribute.tag);
+ if (na != null)
+ na.shiftPc(where, gapLength, exclusive);
+
+ LocalVariableAttribute va = (LocalVariableAttribute)ca.getAttribute(
+ LocalVariableAttribute.tag);
+ if (va != null)
+ va.shiftPc(where, gapLength, exclusive);
+
return newcode;
}
diff --git a/src/main/javassist/bytecode/LineNumberAttribute.java b/src/main/javassist/bytecode/LineNumberAttribute.java
index 0a6df55a..6d892aab 100644
--- a/src/main/javassist/bytecode/LineNumberAttribute.java
+++ b/src/main/javassist/bytecode/LineNumberAttribute.java
@@ -103,6 +103,53 @@ public class LineNumberAttribute extends AttributeInfo {
}
/**
+ * Used as a return type of <code>toNearPc()</code>.
+ */
+ static public class Pc {
+ /**
+ * The index into the code array.
+ */
+ public int index;
+ /**
+ * The line number.
+ */
+ public int line;
+ }
+
+ /**
+ * Returns the index into the code array at which the code for
+ * the specified line (or the nearest line after the specified one)
+ * begins.
+ *
+ * @param line the line number.
+ * @return a pair of the index and the line number of the
+ * bytecode at that index.
+ */
+ public Pc toNearPc(int line) {
+ int n = tableLength();
+ int nearPc = 0;
+ int distance = 0;
+ if (n > 0) {
+ distance = lineNumber(0) - line;
+ nearPc = startPc(0);
+ }
+
+ for (int i = 1; i < n; ++i) {
+ int d = lineNumber(i) - line;
+ if ((d < 0 && d > distance)
+ || (d >= 0 && (d < distance || distance < 0))) {
+ distance = d;
+ nearPc = startPc(i);
+ }
+ }
+
+ Pc res = new Pc();
+ res.index = nearPc;
+ res.line = line + distance;
+ return res;
+ }
+
+ /**
* Makes a copy.
*
* @param newCp the constant pool table used by the new copy.
@@ -118,4 +165,17 @@ public class LineNumberAttribute extends AttributeInfo {
LineNumberAttribute attr = new LineNumberAttribute(newCp, dest);
return attr;
}
+
+ /**
+ * Adjusts start_pc if bytecode is inserted in a method body.
+ */
+ void shiftPc(int where, int gapLength, boolean exclusive) {
+ int n = tableLength();
+ for (int i = 0; i < n; ++i) {
+ int pos = i * 4 + 2;
+ int pc = ByteArray.readU16bit(info, pos);
+ if (pc > where || (exclusive && pc == where))
+ ByteArray.write16bit(pc + gapLength, info, pos);
+ }
+ }
}
diff --git a/src/main/javassist/bytecode/LocalVariableAttribute.java b/src/main/javassist/bytecode/LocalVariableAttribute.java
index 74262b67..0bc273d5 100644
--- a/src/main/javassist/bytecode/LocalVariableAttribute.java
+++ b/src/main/javassist/bytecode/LocalVariableAttribute.java
@@ -69,6 +69,22 @@ public class LocalVariableAttribute extends AttributeInfo {
}
/**
+ * Adjusts start_pc and length if bytecode is inserted in a method body.
+ */
+ void shiftPc(int where, int gapLength, boolean exclusive) {
+ int n = tableLength();
+ for (int i = 0; i < n; ++i) {
+ int pos = i * 10 + 2;
+ int pc = ByteArray.readU16bit(info, pos);
+ int len = ByteArray.readU16bit(info, pos + 2);
+ if (pc > where || (exclusive && pc == where))
+ ByteArray.write16bit(pc + gapLength, info, pos);
+ else if (pc + len > where)
+ ByteArray.write16bit(len + gapLength, info, pos + 2);
+ }
+ }
+
+ /**
* Returns <code>local_variable_table[i].name_index</code>.
* This represents the name of the local variable.
*