• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
TransformCall(Transformer next, CtMethod origMethod, CtMethod substMethod)34     public TransformCall(Transformer next, CtMethod origMethod,
35                          CtMethod substMethod)
36     {
37         this(next, origMethod.getName(), substMethod);
38         classname = origMethod.getDeclaringClass().getName();
39     }
40 
TransformCall(Transformer next, String oldMethodName, CtMethod substMethod)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 
initialize(ConstPool cp, CodeAttribute attr)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      */
transform(CtClass clazz, int pos, CodeIterator iterator, ConstPool cp)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 
matchClass(String name, ClassPool pool)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 
match(int c, int pos, CodeIterator iterator, int typedesc, ConstPool cp)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