diff options
author | chiba <chiba@30ef5769-5b8d-40dd-aea6-55b5d6557bb3> | 2005-12-29 16:20:02 +0000 |
---|---|---|
committer | chiba <chiba@30ef5769-5b8d-40dd-aea6-55b5d6557bb3> | 2005-12-29 16:20:02 +0000 |
commit | 07eda55dcc1b4e4e9f9d54beb5722709bd92e4f5 (patch) | |
tree | 874e801504912bd9dcdabb093b5bc90f00c1ddca | |
parent | c9ab3dda7e40a5fa6fa83757a347d9256d2b77d9 (diff) | |
download | javassist-07eda55dcc1b4e4e9f9d54beb5722709bd92e4f5.tar.gz javassist-07eda55dcc1b4e4e9f9d54beb5722709bd92e4f5.zip |
implemented recursive replace() for ExprEditor.
git-svn-id: http://anonsvn.jboss.org/repos/javassist/trunk@227 30ef5769-5b8d-40dd-aea6-55b5d6557bb3
-rw-r--r-- | src/main/javassist/bytecode/CodeIterator.java | 12 | ||||
-rw-r--r-- | src/main/javassist/expr/Expr.java | 56 | ||||
-rw-r--r-- | src/main/javassist/expr/ExprEditor.java | 228 |
3 files changed, 196 insertions, 100 deletions
diff --git a/src/main/javassist/bytecode/CodeIterator.java b/src/main/javassist/bytecode/CodeIterator.java index ab9ce7d9..eb10c871 100644 --- a/src/main/javassist/bytecode/CodeIterator.java +++ b/src/main/javassist/bytecode/CodeIterator.java @@ -154,6 +154,18 @@ public class CodeIterator implements Opcode { } /** + * Obtains the value that the next call + * to <code>next()</code> will return. + * + * <p>This method is side-effects free. + * Successive calls to <code>lookAhead()</code> return the + * same value until <code>next()</code> is called. + */ + public int lookAhead() { + return currentPos; + } + + /** * Moves to the instruction for * either <code>super()</code> or <code>this()</code>. * diff --git a/src/main/javassist/expr/Expr.java b/src/main/javassist/expr/Expr.java index 7760aa6b..d0a42b74 100644 --- a/src/main/javassist/expr/Expr.java +++ b/src/main/javassist/expr/Expr.java @@ -43,15 +43,10 @@ import java.util.LinkedList; */ public abstract class Expr implements Opcode { int currentPos; - CodeIterator iterator; - CtClass thisClass; - MethodInfo thisMethod; - boolean edited; - int maxLocals, maxStack; static final String javaLangObject = "java.lang.Object"; @@ -252,6 +247,32 @@ public abstract class Expr implements Opcode { } } + /** + * Replaces this expression with the bytecode derived from + * the given source text. + * + * @param statement a Java statement. + */ + public abstract void replace(String statement) throws CannotCompileException; + + /** + * Replaces this expression with the bytecode derived from + * the given source text and <code>ExprEditor</code>. + * + * @param statement a Java statement. + * @param recursive if not null, the substituted bytecode + * is recursively processed by the given + * <code>ExprEditor</code>. + * @since 3.1 + */ + public void replace(String statement, ExprEditor recursive) + throws CannotCompileException + { + replace(statement); + if (recursive != null) + runEditor(recursive, iterator); + } + protected void replace0(int pos, Bytecode bytecode, int size) throws BadBytecode { byte[] code = bytecode.get(); @@ -268,4 +289,29 @@ public abstract class Expr implements Opcode { maxLocals = bytecode.getMaxLocals(); maxStack = bytecode.getMaxStack(); } + + protected void runEditor(ExprEditor ed, CodeIterator oldIterator) + throws CannotCompileException + { + CodeAttribute codeAttr = oldIterator.get(); + int orgLocals = codeAttr.getMaxLocals(); + int orgStack = codeAttr.getMaxStack(); + int newLocals = locals(); + codeAttr.setMaxStack(stack()); + codeAttr.setMaxLocals(newLocals); + ExprEditor.LoopContext context + = new ExprEditor.LoopContext(newLocals); + CodeIterator iterator = codeAttr.iterator(); + iterator.move(currentPos); + int size = iterator.getCodeLength(); + int endPos = oldIterator.lookAhead(); + if (ed.doit(thisClass, thisMethod, context, iterator, endPos)) + edited = true; + + oldIterator.move(endPos + iterator.getCodeLength() - size); + codeAttr.setMaxLocals(orgLocals); + codeAttr.setMaxStack(orgStack); + maxLocals = context.maxLocals; + maxStack += context.maxStack; + } } diff --git a/src/main/javassist/expr/ExprEditor.java b/src/main/javassist/expr/ExprEditor.java index 475ab692..c18e426b 100644 --- a/src/main/javassist/expr/ExprEditor.java +++ b/src/main/javassist/expr/ExprEditor.java @@ -72,18 +72,6 @@ public class ExprEditor { */ public ExprEditor() {} - static class NewOp { - NewOp next; - int pos; - String type; - - NewOp(NewOp n, int p, String t) { - next = n; - pos = p; - type = t; - } - } - /** * Undocumented method. Do not use; internal-use only. */ @@ -96,85 +84,11 @@ public class ExprEditor { CodeIterator iterator = codeAttr.iterator(); boolean edited = false; - int maxLocals = codeAttr.getMaxLocals(); - int maxStack = 0; - - NewOp newList = null; - ConstPool cp = minfo.getConstPool(); + LoopContext context = new LoopContext(codeAttr.getMaxLocals()); while (iterator.hasNext()) - try { - Expr expr = null; - int pos = iterator.next(); - int c = iterator.byteAt(pos); - - if (c < Opcode.GETSTATIC) // c < 178 - /* skip */; - else if (c < Opcode.NEWARRAY) { // c < 188 - if (c == Opcode.INVOKESTATIC - || c == Opcode.INVOKEINTERFACE - || c == Opcode.INVOKEVIRTUAL) { - expr = new MethodCall(pos, iterator, clazz, minfo); - edit((MethodCall)expr); - } - else if (c == Opcode.GETFIELD || c == Opcode.GETSTATIC - || c == Opcode.PUTFIELD - || c == Opcode.PUTSTATIC) { - expr = new FieldAccess(pos, iterator, clazz, minfo, c); - edit((FieldAccess)expr); - } - else if (c == Opcode.NEW) { - int index = iterator.u16bitAt(pos + 1); - newList = new NewOp(newList, pos, - cp.getClassInfo(index)); - } - else if (c == Opcode.INVOKESPECIAL) { - if (newList != null && cp.isConstructor(newList.type, - iterator.u16bitAt(pos + 1)) > 0) { - expr = new NewExpr(pos, iterator, clazz, minfo, - newList.type, newList.pos); - edit((NewExpr)expr); - newList = newList.next; - } - else { - MethodCall mcall = new MethodCall(pos, iterator, clazz, minfo); - if (mcall.getMethodName().equals(MethodInfo.nameInit)) { - ConstructorCall ccall = new ConstructorCall(pos, iterator, clazz, minfo); - expr = ccall; - edit(ccall); - } - else { - expr = mcall; - edit(mcall); - } - } - } - } - else { // c >= 188 - if (c == Opcode.NEWARRAY || c == Opcode.ANEWARRAY - || c == Opcode.MULTIANEWARRAY) { - expr = new NewArray(pos, iterator, clazz, minfo, c); - edit((NewArray)expr); - } - else if (c == Opcode.INSTANCEOF) { - expr = new Instanceof(pos, iterator, clazz, minfo); - edit((Instanceof)expr); - } - else if (c == Opcode.CHECKCAST) { - expr = new Cast(pos, iterator, clazz, minfo); - edit((Cast)expr); - } - } - - if (expr != null && expr.edited()) { - edited = true; - maxLocals = max(maxLocals, expr.locals()); - maxStack = max(maxStack, expr.stack()); - } - } - catch (BadBytecode e) { - throw new CannotCompileException(e); - } + if (loopBody(iterator, clazz, minfo, context)) + edited = true; ExceptionTable et = codeAttr.getExceptionTable(); int n = et.size(); @@ -183,18 +97,142 @@ public class ExprEditor { edit(h); if (h.edited()) { edited = true; - maxLocals = max(maxLocals, h.locals()); - maxStack = max(maxStack, h.stack()); + context.updateMax(h.locals(), h.stack()); } } - codeAttr.setMaxLocals(maxLocals); - codeAttr.setMaxStack(codeAttr.getMaxStack() + maxStack); + codeAttr.setMaxLocals(context.maxLocals); + codeAttr.setMaxStack(codeAttr.getMaxStack() + context.maxStack); + return edited; + } + + /** + * Visits each bytecode in the given range. + */ + boolean doit(CtClass clazz, MethodInfo minfo, LoopContext context, + CodeIterator iterator, int endPos) + throws CannotCompileException + { + boolean edited = false; + + while (iterator.hasNext() && iterator.lookAhead() < endPos) + if (loopBody(iterator, clazz, minfo, context)) + edited = true; + return edited; } - private int max(int i, int j) { - return i > j ? i : j; + final static class NewOp { + NewOp next; + int pos; + String type; + + NewOp(NewOp n, int p, String t) { + next = n; + pos = p; + type = t; + } + } + + final static class LoopContext { + NewOp newList; + int maxLocals; + int maxStack; + + LoopContext(int locals) { + maxLocals = locals; + maxStack = 0; + newList = null; + } + + void updateMax(int locals, int stack) { + if (maxLocals < locals) + maxLocals = locals; + + if (maxStack < stack) + maxStack = stack; + } + } + + final boolean loopBody(CodeIterator iterator, CtClass clazz, + MethodInfo minfo, LoopContext context) + throws CannotCompileException + { + try { + Expr expr = null; + int pos = iterator.next(); + int c = iterator.byteAt(pos); + + if (c < Opcode.GETSTATIC) // c < 178 + /* skip */; + else if (c < Opcode.NEWARRAY) { // c < 188 + if (c == Opcode.INVOKESTATIC + || c == Opcode.INVOKEINTERFACE + || c == Opcode.INVOKEVIRTUAL) { + expr = new MethodCall(pos, iterator, clazz, minfo); + edit((MethodCall)expr); + } + else if (c == Opcode.GETFIELD || c == Opcode.GETSTATIC + || c == Opcode.PUTFIELD + || c == Opcode.PUTSTATIC) { + expr = new FieldAccess(pos, iterator, clazz, minfo, c); + edit((FieldAccess)expr); + } + else if (c == Opcode.NEW) { + int index = iterator.u16bitAt(pos + 1); + context.newList = new NewOp(context.newList, pos, + minfo.getConstPool().getClassInfo(index)); + } + else if (c == Opcode.INVOKESPECIAL) { + NewOp newList = context.newList; + if (newList != null + && minfo.getConstPool().isConstructor(newList.type, + iterator.u16bitAt(pos + 1)) > 0) { + expr = new NewExpr(pos, iterator, clazz, minfo, + newList.type, newList.pos); + edit((NewExpr)expr); + context.newList = newList.next; + } + else { + MethodCall mcall = new MethodCall(pos, iterator, clazz, minfo); + if (mcall.getMethodName().equals(MethodInfo.nameInit)) { + ConstructorCall ccall = new ConstructorCall(pos, iterator, clazz, minfo); + expr = ccall; + edit(ccall); + } + else { + expr = mcall; + edit(mcall); + } + } + } + } + else { // c >= 188 + if (c == Opcode.NEWARRAY || c == Opcode.ANEWARRAY + || c == Opcode.MULTIANEWARRAY) { + expr = new NewArray(pos, iterator, clazz, minfo, c); + edit((NewArray)expr); + } + else if (c == Opcode.INSTANCEOF) { + expr = new Instanceof(pos, iterator, clazz, minfo); + edit((Instanceof)expr); + } + else if (c == Opcode.CHECKCAST) { + expr = new Cast(pos, iterator, clazz, minfo); + edit((Cast)expr); + } + } + + if (expr != null && expr.edited()) { + context.updateMax(expr.locals(), expr.stack()); + return true; + } + else + return false; + } + catch (BadBytecode e) { + throw new CannotCompileException(e); + } } /** |