diff options
-rw-r--r-- | Readme.html | 1 | ||||
-rw-r--r-- | src/main/javassist/CtBehavior.java | 78 | ||||
-rw-r--r-- | src/main/javassist/bytecode/CodeAttribute.java | 7 | ||||
-rw-r--r-- | src/main/javassist/bytecode/CodeIterator.java | 21 | ||||
-rw-r--r-- | src/main/javassist/bytecode/LineNumberAttribute.java | 60 | ||||
-rw-r--r-- | src/main/javassist/bytecode/LocalVariableAttribute.java | 16 |
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. * |