/* ==================================================================== * The Apache Software License, Version 1.1 * * Copyright (c) 2001 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Apache" and "Apache Software Foundation" and * "Apache BCEL" must not be used to endorse or promote products * derived from this software without prior written permission. For * written permission, please contact apache@apache.org. * * 5. Products derived from this software may not be called "Apache", * "Apache BCEL", nor may "Apache" appear in their name, without * prior written permission of the Apache Software Foundation. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * . */ package org.aspectj.apache.bcel.classfile; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.util.HashMap; import java.util.Map; import com.sun.org.apache.bcel.internal.Const; import org.aspectj.apache.bcel.Constants; import org.aspectj.apache.bcel.generic.ArrayType; import org.aspectj.apache.bcel.generic.ObjectType; /** * This class represents the constant pool, i.e., a table of constants, of a parsed classfile. It may contain null references, due * to the JVM specification that skips an entry after an 8-byte constant (double, long) entry. */ public class ConstantPool implements Node { private Constant[] pool; private int poolSize; // number of entries in the pool (could be < pool.length as the array is resized in 'chunks') private Map utf8Cache = new HashMap<>(); private Map methodCache = new HashMap<>(); private Map fieldCache = new HashMap<>(); public int getSize() { return poolSize; } public ConstantPool() { pool = new Constant[10]; poolSize = 0; } public ConstantPool(Constant[] constants) { pool = constants; poolSize = (constants == null ? 0 : constants.length); } ConstantPool(DataInputStream file) throws IOException { byte tag; poolSize = file.readUnsignedShort(); pool = new Constant[poolSize]; // pool[0] is unused by the compiler and may be used freely by the implementation for (int i = 1; i < poolSize; i++) { pool[i] = Constant.readConstant(file); tag = pool[i].getTag(); if ((tag == Constants.CONSTANT_Double) || (tag == Constants.CONSTANT_Long)) { i++; } } } public Constant getConstant(int index, byte tag) { Constant c = getConstant(index); // if (c == null) throw new ClassFormatException("Constant pool at index " + index + " is null."); if (c.tag == tag) return c; throw new ClassFormatException("Expected class '" + Constants.CONSTANT_NAMES[tag] + "' at index " + index + " and found " + c); } public Constant getConstant(int index) { try { return pool[index]; } catch (ArrayIndexOutOfBoundsException aioobe) { throw new ClassFormatException("Index " + index + " into constant pool (size:" + poolSize + ") is invalid"); } } /** * @return deep copy of this constant pool */ public ConstantPool copy() { Constant[] newConstants = new Constant[poolSize]; // use the correct size for (int i = 1; i < poolSize; i++) { if (pool[i] != null) { newConstants[i] = pool[i].copy(); } } return new ConstantPool(newConstants); } /** * Get string from constant pool and bypass the indirection of `ConstantClass' and `ConstantString' objects. I.e. these classes * have an index field that points to another entry of the constant pool of type `ConstantUtf8' which contains the real data. * * @param index Index in constant pool * @param tag Tag of expected constant, either ConstantClass or ConstantString * @return Contents of string reference * @see ConstantClass * @see ConstantString * @throws ClassFormatException */ public String getConstantString(int index, byte tag) throws ClassFormatException { Constant c = getConstant(index, tag); int i; /* * This switch() is not that elegant, since the two classes have the same contents, they just differ in the name of the * index field variable. But we want to stick to the JVM naming conventions closely though we could have solved these more * elegantly by using the same variable name or by subclassing. */ // OPTIMIZE remove the difference - use the an interface and same index methods for string ref id switch (tag) { case Constants.CONSTANT_Class: i = ((ConstantClass) c).getNameIndex(); break; case Constants.CONSTANT_String: i = ((ConstantString) c).getStringIndex(); break; default: throw new RuntimeException("getConstantString called with illegal tag " + tag); } // Finally get the string from the constant pool c = getConstant(i, Constants.CONSTANT_Utf8); return ((ConstantUtf8) c).getValue(); } /** * Resolve constant to a string representation. */ public String constantToString(Constant c) { String str; int i; switch (c.tag) { case Constants.CONSTANT_Class: i = ((ConstantClass) c).getNameIndex(); c = getConstant(i, Constants.CONSTANT_Utf8); str = Utility.compactClassName(((ConstantUtf8) c).getValue(), false); break; case Constants.CONSTANT_String: i = ((ConstantString) c).getStringIndex(); c = getConstant(i, Constants.CONSTANT_Utf8); str = "\"" + escape(((ConstantUtf8) c).getValue()) + "\""; break; case Constants.CONSTANT_Utf8: case Constants.CONSTANT_Double: case Constants.CONSTANT_Float: case Constants.CONSTANT_Long: case Constants.CONSTANT_Integer: str = ((SimpleConstant) c).getStringValue(); break; case Constants.CONSTANT_NameAndType: str = (constantToString(((ConstantNameAndType) c).getNameIndex(), Constants.CONSTANT_Utf8) + " " + constantToString( ((ConstantNameAndType) c).getSignatureIndex(), Constants.CONSTANT_Utf8)); break; case Constants.CONSTANT_InterfaceMethodref: case Constants.CONSTANT_Methodref: case Constants.CONSTANT_Fieldref: str = (constantToString(((ConstantCP) c).getClassIndex(), Constants.CONSTANT_Class) + "." + constantToString( ((ConstantCP) c).getNameAndTypeIndex(), Constants.CONSTANT_NameAndType)); break; case Constants.CONSTANT_InvokeDynamic: ConstantInvokeDynamic cID = ((ConstantInvokeDynamic)c); return "#"+cID.getBootstrapMethodAttrIndex()+"."+constantToString(cID.getNameAndTypeIndex(), Constants.CONSTANT_NameAndType); case Constants.CONSTANT_Dynamic: ConstantDynamic cD = ((ConstantDynamic)c); return "#"+cD.getBootstrapMethodAttrIndex()+"."+constantToString(cD.getNameAndTypeIndex(), Constants.CONSTANT_NameAndType); case Constants.CONSTANT_MethodHandle: ConstantMethodHandle cMH = ((ConstantMethodHandle)c); return cMH.getReferenceKind()+":"+constantToString(cMH.getReferenceIndex(),Constants.CONSTANT_Methodref); case Constants.CONSTANT_MethodType: ConstantMethodType cMT = (ConstantMethodType)c; return constantToString(cMT.getDescriptorIndex(),Constants.CONSTANT_Utf8); case Constants.CONSTANT_Module: ConstantModule cM = (ConstantModule)c; return "Module:"+constantToString(cM.getNameIndex(),Constants.CONSTANT_Utf8); case Constants.CONSTANT_Package: ConstantPackage cP = (ConstantPackage)c; return "Package:"+constantToString(cP.getNameIndex(),Constants.CONSTANT_Utf8); default: // Never reached throw new RuntimeException("Unknown constant type " + c.tag); } return str; } private static final String escape(String str) { int len = str.length(); StringBuilder buf = new StringBuilder(len + 5); char[] ch = str.toCharArray(); for (int i = 0; i < len; i++) { switch (ch[i]) { case '\n': buf.append("\\n"); break; case '\r': buf.append("\\r"); break; case '\t': buf.append("\\t"); break; case '\b': buf.append("\\b"); break; case '"': buf.append("\\\""); break; default: buf.append(ch[i]); } } return buf.toString(); } public String constantToString(int index, byte tag) { Constant c = getConstant(index, tag); return constantToString(c); } public String constantToString(int index) { return constantToString(getConstant(index)); } @Override public void accept(ClassVisitor v) { v.visitConstantPool(this); } public Constant[] getConstantPool() { return pool; } // TEMPORARY, DONT LIKE PASSING THIS DATA OUT! public void dump(DataOutputStream file) throws IOException { /* * Constants over the size of the constant pool shall not be written out. * This is a redundant measure as the ConstantPoolGen should have already * reported an error back in the situation. */ final int size = Math.min(poolSize, Const.MAX_CP_ENTRIES); file.writeShort(size); for (int i = 1; i < size; i++) if (pool[i] != null) pool[i].dump(file); } public ConstantUtf8 getConstantUtf8(int index) { Constant c = getConstant(index); assert c != null; assert c.tag == Constants.CONSTANT_Utf8; return (ConstantUtf8) c; } public ConstantModule getConstantModule(int index) { Constant c = getConstant(index); assert c != null; assert c.tag == Constants.CONSTANT_Module; return (ConstantModule)c; } public ConstantPackage getConstantPackage(int index) { Constant c = getConstant(index); assert c != null; assert c.tag == Constants.CONSTANT_Package; return (ConstantPackage)c; } public String getConstantString_CONSTANTClass(int index) { ConstantClass c = (ConstantClass) getConstant(index, Constants.CONSTANT_Class); index = c.getNameIndex(); return ((ConstantUtf8) getConstant(index, Constants.CONSTANT_Utf8)).getValue(); } public int getLength() { return poolSize; } @Override public String toString() { StringBuilder buf = new StringBuilder(); for (int i = 1; i < poolSize; i++) buf.append(i).append(") ").append(pool[i]).append("\n"); return buf.toString(); } public int lookupInteger(int n) { for (int i = 1; i < poolSize; i++) { if (pool[i] instanceof ConstantInteger) { ConstantInteger c = (ConstantInteger) pool[i]; if (c.getValue() == n) return i; } } return -1; } public int lookupUtf8(String string) { Integer pos = utf8Cache.get(string); if (pos != null) { return pos; } for (int i = 1; i < poolSize; i++) { Constant c = pool[i]; if (c != null && c.tag == Constants.CONSTANT_Utf8) { if (((ConstantUtf8) c).getValue().equals(string)) { utf8Cache.put(string, i); return i; } } } return -1; } public int lookupClass(String classname) { for (int i = 1; i < poolSize; i++) { Constant c = pool[i]; if (c != null && c.tag == Constants.CONSTANT_Class) { int cIndex = ((ConstantClass) c).getNameIndex(); String cName = ((ConstantUtf8) pool[cIndex]).getValue(); if (cName.equals(classname)) return i; } } return -1; } public int addUtf8(String n) { int ret = lookupUtf8(n); if (ret != -1) return ret; adjustSize(); ret = poolSize; pool[poolSize++] = new ConstantUtf8(n); return ret; } public int addInteger(int n) { int ret = lookupInteger(n); if (ret != -1) return ret; adjustSize(); ret = poolSize; pool[poolSize++] = new ConstantInteger(n); return ret; } public int addArrayClass(ArrayType type) { return addClass(type.getSignature()); } public int addClass(ObjectType type) { return addClass(type.getClassName()); } public int addClass(String classname) { String toAdd = classname.replace('.', '/'); int ret = lookupClass(toAdd); if (ret != -1) return ret; adjustSize(); ConstantClass c = new ConstantClass(addUtf8(toAdd)); ret = poolSize; pool[poolSize++] = c; return ret; } private void adjustSize() { // 3 extra spaces are needed as some entries may take 3 slots if (poolSize + 3 >= Const.MAX_CP_ENTRIES + 1) { throw new IllegalStateException( "The number of constants " + (poolSize + 3) + " is over the size of the constant pool: " + Const.MAX_CP_ENTRIES ); } if (poolSize + 3 >= pool.length) { Constant[] cs = pool; int size = cs.length + 8; // the constant array shall not exceed the size of the constant pool size = Math.min(size, Const.MAX_CP_ENTRIES + 1); pool = new Constant[size]; System.arraycopy(cs, 0, pool, 0, cs.length); } if (poolSize == 0) poolSize = 1; // someone about to do something in here! } public int addFieldref(String class_name, String field_name, String signature) { int ret = lookupFieldref(class_name, field_name, signature); int class_index, name_and_type_index; if (ret != -1) return ret; adjustSize(); class_index = addClass(class_name); name_and_type_index = addNameAndType(field_name, signature); ret = poolSize; pool[poolSize++] = new ConstantFieldref(class_index, name_and_type_index); return ret; } public int lookupFieldref(String searchClassname, String searchFieldname, String searchSignature) { searchClassname = searchClassname.replace('.', '/'); String k = new StringBuilder().append(searchClassname).append(searchFieldname).append(searchSignature).toString(); Integer pos = fieldCache.get(k); if (pos != null) return pos; for (int i = 1; i < poolSize; i++) { Constant c = pool[i]; if (c != null && c.tag == Constants.CONSTANT_Fieldref) { ConstantFieldref cfr = (ConstantFieldref) c; ConstantNameAndType cnat = (ConstantNameAndType) pool[cfr.getNameAndTypeIndex()]; // check the class int cIndex = cfr.getClassIndex(); ConstantClass cc = (ConstantClass) pool[cIndex]; String cName = ((ConstantUtf8) pool[cc.getNameIndex()]).getValue(); if (!cName.equals(searchClassname)) continue; // check the name and type String name = ((ConstantUtf8) pool[cnat.getNameIndex()]).getValue(); if (!name.equals(searchFieldname)) continue; // not this one String typeSignature = ((ConstantUtf8) pool[cnat.getSignatureIndex()]).getValue(); if (!typeSignature.equals(searchSignature)) continue; fieldCache.put(k, i); return i; } } return -1; } public int addNameAndType(String name, String signature) { int ret = lookupNameAndType(name, signature); if (ret != -1) return ret; adjustSize(); int name_index = addUtf8(name); int signature_index = addUtf8(signature); ret = poolSize; pool[poolSize++] = new ConstantNameAndType(name_index, signature_index); return ret; } public int lookupNameAndType(String searchName, String searchTypeSignature) { for (int i = 1; i < poolSize; i++) { Constant c = pool[i]; if (c != null && c.tag == Constants.CONSTANT_NameAndType) { ConstantNameAndType cnat = (ConstantNameAndType) c; String name = ((ConstantUtf8) pool[cnat.getNameIndex()]).getValue(); if (!name.equals(searchName)) continue; // not this one String typeSignature = ((ConstantUtf8) pool[cnat.getSignatureIndex()]).getValue(); if (!typeSignature.equals(searchTypeSignature)) continue; return i; } } return -1; } public int addFloat(float f) { int ret = lookupFloat(f); if (ret != -1) return ret; adjustSize(); ret = poolSize; pool[poolSize++] = new ConstantFloat(f); return ret; } public int lookupFloat(float f) { int bits = Float.floatToIntBits(f); for (int i = 1; i < poolSize; i++) { Constant c = pool[i]; if (c != null && c.tag == Constants.CONSTANT_Float) { ConstantFloat cf = (ConstantFloat) c; if (Float.floatToIntBits(cf.getValue()) == bits) return i; } } return -1; } public int addDouble(double d) { int ret = lookupDouble(d); if (ret != -1) return ret; adjustSize(); ret = poolSize; pool[poolSize] = new ConstantDouble(d); poolSize += 2; return ret; } public int lookupDouble(double d) { long bits = Double.doubleToLongBits(d); for (int i = 1; i < poolSize; i++) { Constant c = pool[i]; if (c != null && c.tag == Constants.CONSTANT_Double) { ConstantDouble cf = (ConstantDouble) c; if (Double.doubleToLongBits(cf.getValue()) == bits) return i; } } return -1; } public int addLong(long l) { int ret = lookupLong(l); if (ret != -1) return ret; adjustSize(); ret = poolSize; pool[poolSize] = new ConstantLong(l); poolSize += 2; return ret; } public int lookupString(String s) { for (int i = 1; i < poolSize; i++) { Constant c = pool[i]; if (c != null && c.tag == Constants.CONSTANT_String) { ConstantString cs = (ConstantString) c; ConstantUtf8 cu8 = (ConstantUtf8) pool[cs.getStringIndex()]; if (cu8.getValue().equals(s)) return i; } } return -1; } public int addString(String str) { int ret = lookupString(str); if (ret != -1) return ret; int utf8 = addUtf8(str); adjustSize(); ConstantString s = new ConstantString(utf8); ret = poolSize; pool[poolSize++] = s; return ret; } public int lookupLong(long l) { for (int i = 1; i < poolSize; i++) { Constant c = pool[i]; if (c != null && c.tag == Constants.CONSTANT_Long) { ConstantLong cf = (ConstantLong) c; if (cf.getValue() == l) return i; } } return -1; } public int addConstant(Constant c, ConstantPool cp) { Constant[] constants = cp.getConstantPool(); switch (c.getTag()) { case Constants.CONSTANT_String: { ConstantString s = (ConstantString) c; ConstantUtf8 u8 = (ConstantUtf8) constants[s.getStringIndex()]; return addString(u8.getValue()); } case Constants.CONSTANT_Class: { ConstantClass s = (ConstantClass) c; ConstantUtf8 u8 = (ConstantUtf8) constants[s.getNameIndex()]; return addClass(u8.getValue()); } case Constants.CONSTANT_NameAndType: { ConstantNameAndType n = (ConstantNameAndType) c; ConstantUtf8 u8 = (ConstantUtf8) constants[n.getNameIndex()]; ConstantUtf8 u8_2 = (ConstantUtf8) constants[n.getSignatureIndex()]; return addNameAndType(u8.getValue(), u8_2.getValue()); } case Constants.CONSTANT_InvokeDynamic: { ConstantInvokeDynamic cid = (ConstantInvokeDynamic)c; int index1 = cid.getBootstrapMethodAttrIndex(); ConstantNameAndType cnat = (ConstantNameAndType)constants[cid.getNameAndTypeIndex()]; ConstantUtf8 name = (ConstantUtf8) constants[cnat.getNameIndex()]; ConstantUtf8 signature = (ConstantUtf8) constants[cnat.getSignatureIndex()]; int index2 = addNameAndType(name.getValue(), signature.getValue()); return addInvokeDynamic(index1,index2); } case Constants.CONSTANT_Dynamic: { ConstantDynamic cd = (ConstantDynamic)c; int index1 = cd.getBootstrapMethodAttrIndex(); ConstantNameAndType cnat = (ConstantNameAndType)constants[cd.getNameAndTypeIndex()]; ConstantUtf8 name = (ConstantUtf8) constants[cnat.getNameIndex()]; ConstantUtf8 signature = (ConstantUtf8) constants[cnat.getSignatureIndex()]; int index2 = addNameAndType(name.getValue(), signature.getValue()); return addConstantDynamic(index1,index2); } case Constants.CONSTANT_MethodHandle: ConstantMethodHandle cmh = (ConstantMethodHandle)c; return addMethodHandle(cmh.getReferenceKind(),addConstant(constants[cmh.getReferenceIndex()],cp)); case Constants.CONSTANT_Utf8: return addUtf8(((ConstantUtf8) c).getValue()); case Constants.CONSTANT_Double: return addDouble(((ConstantDouble) c).getValue()); case Constants.CONSTANT_Float: return addFloat(((ConstantFloat) c).getValue()); case Constants.CONSTANT_Long: return addLong(((ConstantLong) c).getValue()); case Constants.CONSTANT_Integer: return addInteger(((ConstantInteger) c).getValue()); case Constants.CONSTANT_MethodType: ConstantMethodType cmt = (ConstantMethodType)c; return addMethodType(addConstant(constants[cmt.getDescriptorIndex()],cp)); case Constants.CONSTANT_InterfaceMethodref: case Constants.CONSTANT_Methodref: case Constants.CONSTANT_Fieldref: { ConstantCP m = (ConstantCP) c; ConstantClass clazz = (ConstantClass) constants[m.getClassIndex()]; ConstantNameAndType n = (ConstantNameAndType) constants[m.getNameAndTypeIndex()]; ConstantUtf8 u8 = (ConstantUtf8) constants[clazz.getNameIndex()]; String class_name = u8.getValue().replace('/', '.'); u8 = (ConstantUtf8) constants[n.getNameIndex()]; String name = u8.getValue(); u8 = (ConstantUtf8) constants[n.getSignatureIndex()]; String signature = u8.getValue(); switch (c.getTag()) { case Constants.CONSTANT_InterfaceMethodref: return addInterfaceMethodref(class_name, name, signature); case Constants.CONSTANT_Methodref: return addMethodref(class_name, name, signature); // OPTIMIZE indicate it should be cached! case Constants.CONSTANT_Fieldref: return addFieldref(class_name, name, signature); default: // Never reached throw new RuntimeException("Unknown constant type " + c); } } default: // Never reached throw new RuntimeException("Unknown constant type " + c); } } public int addMethodHandle(byte referenceKind, int referenceIndex) { adjustSize(); int ret = poolSize; pool[poolSize++] = new ConstantMethodHandle(referenceKind, referenceIndex); return ret; } public int addMethodType(int descriptorIndex) { adjustSize(); int ret = poolSize; pool[poolSize++] = new ConstantMethodType(descriptorIndex); return ret; } // OPTIMIZE should put it in the cache now public int addMethodref(String class_name, String method_name, String signature) { int ret, class_index, name_and_type_index; if ((ret = lookupMethodref(class_name, method_name, signature)) != -1) return ret; // Already in CP adjustSize(); name_and_type_index = addNameAndType(method_name, signature); class_index = addClass(class_name); ret = poolSize; pool[poolSize++] = new ConstantMethodref(class_index, name_and_type_index); return ret; } public int addInvokeDynamic(int bootstrapMethodIndex, int constantNameAndTypeIndex) { adjustSize(); int ret = poolSize; pool[poolSize++] = new ConstantInvokeDynamic(bootstrapMethodIndex, constantNameAndTypeIndex); return ret; } public int addConstantDynamic(int bootstrapMethodIndex, int constantNameAndTypeIndex) { adjustSize(); int ret = poolSize; pool[poolSize++] = new ConstantDynamic(bootstrapMethodIndex, constantNameAndTypeIndex); return ret; } public int addInterfaceMethodref(String class_name, String method_name, String signature) { int ret = lookupInterfaceMethodref(class_name, method_name, signature); int class_index, name_and_type_index; if (ret != -1) return ret; adjustSize(); class_index = addClass(class_name); name_and_type_index = addNameAndType(method_name, signature); ret = poolSize; pool[poolSize++] = new ConstantInterfaceMethodref(class_index, name_and_type_index); return ret; } public int lookupInterfaceMethodref(String searchClassname, String searchMethodName, String searchSignature) { searchClassname = searchClassname.replace('.', '/'); for (int i = 1; i < poolSize; i++) { Constant c = pool[i]; if (c != null && c.tag == Constants.CONSTANT_InterfaceMethodref) { ConstantInterfaceMethodref cfr = (ConstantInterfaceMethodref) c; ConstantClass cc = (ConstantClass) pool[cfr.getClassIndex()]; String cName = ((ConstantUtf8) pool[cc.getNameIndex()]).getValue(); if (!cName.equals(searchClassname)) continue; // check the name and type ConstantNameAndType cnat = (ConstantNameAndType) pool[cfr.getNameAndTypeIndex()]; String name = ((ConstantUtf8) pool[cnat.getNameIndex()]).getValue(); if (!name.equals(searchMethodName)) continue; // not this one String typeSignature = ((ConstantUtf8) pool[cnat.getSignatureIndex()]).getValue(); if (!typeSignature.equals(searchSignature)) continue; return i; } } return -1; } public int lookupMethodref(String searchClassname, String searchMethodName, String searchSignature) { String key = new StringBuilder().append(searchClassname).append(searchMethodName).append(searchSignature).toString(); Integer cached = methodCache.get(key); if (cached != null) return cached; searchClassname = searchClassname.replace('.', '/'); for (int i = 1; i < poolSize; i++) { Constant c = pool[i]; if (c != null && c.tag == Constants.CONSTANT_Methodref) { ConstantMethodref cfr = (ConstantMethodref) c; ConstantNameAndType cnat = (ConstantNameAndType) pool[cfr.getNameAndTypeIndex()]; // check the class int cIndex = cfr.getClassIndex(); ConstantClass cc = (ConstantClass) pool[cIndex]; String cName = ((ConstantUtf8) pool[cc.getNameIndex()]).getValue(); if (!cName.equals(searchClassname)) continue; // check the name and type String name = ((ConstantUtf8) pool[cnat.getNameIndex()]).getValue(); if (!name.equals(searchMethodName)) continue; // not this one String typeSignature = ((ConstantUtf8) pool[cnat.getSignatureIndex()]).getValue(); if (!typeSignature.equals(searchSignature)) continue; methodCache.put(key, i); return i; } } return -1; } public ConstantPool getFinalConstantPool() { Constant[] cs = new Constant[poolSize]; // create it the exact size we need System.arraycopy(pool, 0, cs, 0, poolSize); return new ConstantPool(cs); } public String getModuleName(int moduleIndex) { return getConstantModule(moduleIndex).getModuleName(this); } public String getPackageName(int packageIndex) { return getConstantPackage(packageIndex).getPackageName(this); } }