]> source.dussan.org Git - javassist.git/commitdiff
implemented recursive replace() for ExprEditor.
authorchiba <chiba@30ef5769-5b8d-40dd-aea6-55b5d6557bb3>
Thu, 29 Dec 2005 16:20:02 +0000 (16:20 +0000)
committerchiba <chiba@30ef5769-5b8d-40dd-aea6-55b5d6557bb3>
Thu, 29 Dec 2005 16:20:02 +0000 (16:20 +0000)
git-svn-id: http://anonsvn.jboss.org/repos/javassist/trunk@227 30ef5769-5b8d-40dd-aea6-55b5d6557bb3

src/main/javassist/bytecode/CodeIterator.java
src/main/javassist/expr/Expr.java
src/main/javassist/expr/ExprEditor.java

index ab9ce7d92f2d9fc5da5a4f4982f582ef76155616..eb10c871b1805cdf311588b655e5cf0fadf2f8d7 100644 (file)
@@ -153,6 +153,18 @@ public class CodeIterator implements Opcode {
         return pos;
     }
 
+    /**
+     * 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>.
index 7760aa6b416410da10cf39768cd6a16223bab31c..d0a42b7405e305e3ed07e24b5c4082abd4ff13b4 100644 (file)
@@ -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;
+    }
 }
index 475ab69254deb31f0dfb558b37989ca2d672ad03..c18e426b1b2e40a583d0043c486c8fdd598019e3 100644 (file)
@@ -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);
+        }
     }
 
     /**