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