Home | History | Annotate | Download | only in convert
      1 /*
      2  * Javassist, a Java-bytecode translator toolkit.
      3  * Copyright (C) 1999-2007 Shigeru Chiba. All Rights Reserved.
      4  *
      5  * The contents of this file are subject to the Mozilla Public License Version
      6  * 1.1 (the "License"); you may not use this file except in compliance with
      7  * the License.  Alternatively, the contents of this file may be used under
      8  * the terms of the GNU Lesser General Public License Version 2.1 or later.
      9  *
     10  * Software distributed under the License is distributed on an "AS IS" basis,
     11  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
     12  * for the specific language governing rights and limitations under the
     13  * License.
     14  */
     15 
     16 package javassist.convert;
     17 
     18 import javassist.CtClass;
     19 import javassist.CtMethod;
     20 import javassist.ClassPool;
     21 import javassist.Modifier;
     22 import javassist.NotFoundException;
     23 import javassist.bytecode.*;
     24 
     25 public class TransformCall extends Transformer {
     26     protected String classname, methodname, methodDescriptor;
     27     protected String newClassname, newMethodname;
     28     protected boolean newMethodIsPrivate;
     29 
     30     /* cache */
     31     protected int newIndex;
     32     protected ConstPool constPool;
     33 
     34     public TransformCall(Transformer next, CtMethod origMethod,
     35                          CtMethod substMethod)
     36     {
     37         this(next, origMethod.getName(), substMethod);
     38         classname = origMethod.getDeclaringClass().getName();
     39     }
     40 
     41     public TransformCall(Transformer next, String oldMethodName,
     42                          CtMethod substMethod)
     43     {
     44         super(next);
     45         methodname = oldMethodName;
     46         methodDescriptor = substMethod.getMethodInfo2().getDescriptor();
     47         classname = newClassname = substMethod.getDeclaringClass().getName();
     48         newMethodname = substMethod.getName();
     49         constPool = null;
     50         newMethodIsPrivate = Modifier.isPrivate(substMethod.getModifiers());
     51     }
     52 
     53     public void initialize(ConstPool cp, CodeAttribute attr) {
     54         if (constPool != cp)
     55             newIndex = 0;
     56     }
     57 
     58     /**
     59      * Modify INVOKEINTERFACE, INVOKESPECIAL, INVOKESTATIC and INVOKEVIRTUAL
     60      * so that a different method is invoked.  The class name in the operand
     61      * of these instructions might be a subclass of the target class specified
     62      * by <code>classname</code>.   This method transforms the instruction
     63      * in that case unless the subclass overrides the target method.
     64      */
     65     public int transform(CtClass clazz, int pos, CodeIterator iterator,
     66                          ConstPool cp) throws BadBytecode
     67     {
     68         int c = iterator.byteAt(pos);
     69         if (c == INVOKEINTERFACE || c == INVOKESPECIAL
     70                         || c == INVOKESTATIC || c == INVOKEVIRTUAL) {
     71             int index = iterator.u16bitAt(pos + 1);
     72             String cname = cp.eqMember(methodname, methodDescriptor, index);
     73             if (cname != null && matchClass(cname, clazz.getClassPool())) {
     74                 int ntinfo = cp.getMemberNameAndType(index);
     75                 pos = match(c, pos, iterator,
     76                             cp.getNameAndTypeDescriptor(ntinfo), cp);
     77             }
     78         }
     79 
     80         return pos;
     81     }
     82 
     83     private boolean matchClass(String name, ClassPool pool) {
     84         if (classname.equals(name))
     85             return true;
     86 
     87         try {
     88             CtClass clazz = pool.get(name);
     89             CtClass declClazz = pool.get(classname);
     90             if (clazz.subtypeOf(declClazz))
     91                 try {
     92                     CtMethod m = clazz.getMethod(methodname, methodDescriptor);
     93                     return m.getDeclaringClass().getName().equals(classname);
     94                 }
     95                 catch (NotFoundException e) {
     96                     // maybe the original method has been removed.
     97                     return true;
     98                 }
     99         }
    100         catch (NotFoundException e) {
    101             return false;
    102         }
    103 
    104         return false;
    105     }
    106 
    107     protected int match(int c, int pos, CodeIterator iterator,
    108                         int typedesc, ConstPool cp) throws BadBytecode
    109     {
    110         if (newIndex == 0) {
    111             int nt = cp.addNameAndTypeInfo(cp.addUtf8Info(newMethodname),
    112                                            typedesc);
    113             int ci = cp.addClassInfo(newClassname);
    114             if (c == INVOKEINTERFACE)
    115                 newIndex = cp.addInterfaceMethodrefInfo(ci, nt);
    116             else {
    117                 if (newMethodIsPrivate && c == INVOKEVIRTUAL)
    118                     iterator.writeByte(INVOKESPECIAL, pos);
    119 
    120                 newIndex = cp.addMethodrefInfo(ci, nt);
    121             }
    122 
    123             constPool = cp;
    124         }
    125 
    126         iterator.write16bit(newIndex, pos + 1);
    127         return pos;
    128     }
    129 }
    130