--- /dev/null
+/*\r
+\r
+ Derby - Class org.apache.derby.iapi.services.classfile.ClassHolder\r
+\r
+ Licensed to the Apache Software Foundation (ASF) under one or more\r
+ contributor license agreements. See the NOTICE file distributed with\r
+ this work for additional information regarding copyright ownership.\r
+ The ASF licenses this file to you under the Apache License, Version 2.0\r
+ (the "License"); you may not use this file except in compliance with\r
+ the License. You may obtain a copy of the License at\r
+\r
+ http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+ Unless required by applicable law or agreed to in writing, software\r
+ distributed under the License is distributed on an "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ See the License for the specific language governing permissions and\r
+ limitations under the License.\r
+\r
+ */\r
+\r
+package org.apache.derby.iapi.services.classfile;\r
+\r
+import org.apache.derby.iapi.services.sanity.SanityManager;\r
+\r
+\r
+import java.io.InputStream;\r
+import java.io.OutputStream;\r
+import java.util.Enumeration;\r
+\r
+import java.io.IOException;\r
+import java.util.Vector;\r
+\r
+import org.apache.derby.iapi.util.ByteArray;\r
+import org.apache.derby.iapi.services.classfile.VMDescriptor;\r
+import org.apache.derby.iapi.services.classfile.VMDescriptor;\r
+\r
+import java.util.Hashtable;\r
+import java.util.Vector;\r
+import java.util.Enumeration;\r
+\r
+\r
+/** Based upon "THE class FILE FORMAT" chapter of "The Java Virtual Machine Specification"\r
+ corresponding to version 1.0.2 of the Java Virtual Machine and 1.0.2 of the\r
+ Java Language Specification.\r
+\r
+ ISBN 0-201-63452-X, September 1996.\r
+ */\r
+\r
+public class ClassHolder {\r
+\r
+\r
+ /*\r
+ ** Constants.\r
+ */\r
+\r
+ /*\r
+ ** Fields\r
+ */\r
+ \r
+ /**\r
+ * Minor class format number defaults to \r
+ * VMDescriptor.JAVA_CLASS_FORMAT_MINOR_VERSION\r
+ * which currently corresponds to a really old (JDK 1.0.2) setting.\r
+ * The default major and minor value is used by the generated code for Derby's\r
+ * SQL statements. Currently there is no need to bump the version\r
+ * number as the generated code does not take advantage of any of the\r
+ * new elements in the class file format. If such a need exists then\r
+ * this can be bumped. One issue is that the change in format numbers\r
+ * is not well documented.\r
+ */\r
+ protected int minor_version = VMDescriptor.JAVA_CLASS_FORMAT_MINOR_VERSION;\r
+\r
+ /**\r
+ * Minor class format number defaults to \r
+ * VMDescriptor.JAVA_CLASS_FORMAT_MAJOR_VERSION\r
+ */\r
+ protected int major_version = VMDescriptor.JAVA_CLASS_FORMAT_MAJOR_VERSION;\r
+ \r
+ protected int access_flags;\r
+ protected int this_class;\r
+ protected int super_class;\r
+\r
+ // protected InterfacesArray interfaces; // can be null\r
+ protected int[] interfaces; //can be null\r
+\r
+ protected MemberTable field_info; // can be null\r
+ protected MemberTable method_info; // can be null\r
+ protected Attributes attribute_info; // can be null\r
+\r
+ /*\r
+ ** Fields for Constant Pool Table\r
+ */\r
+ protected Hashtable cptHashTable;\r
+ protected Vector cptEntries;\r
+ private int cptEstimatedSize;\r
+\r
+ /**\r
+ Used to search for index entries to avoid object allocation\r
+ in the case a referecne already exists.\r
+ */\r
+ private final CONSTANT_Index_info searchIndex = new CONSTANT_Index_info(0, 0, 0);\r
+\r
+ /*\r
+ ** Constructors.\r
+ */\r
+\r
+ protected ClassHolder(int estimatedConstantPoolCount) {\r
+ // Constant Pool Information\r
+ // 100 is the estimate of the number of entries that will be generated\r
+ cptEntries = new Vector(estimatedConstantPoolCount);\r
+ cptHashTable = new Hashtable(estimatedConstantPoolCount, (float)0.75);\r
+\r
+ // reserve the 0'th constant pool entry\r
+ cptEntries.setSize(1);\r
+ }\r
+\r
+\r
+ /**\r
+ This will not define a constructor -- it is up\r
+ to the caller to add at least one.\r
+ */\r
+\r
+ public ClassHolder(String fullyQualifiedName, String superClassName,\r
+ int modifiers) {\r
+\r
+ this(100);\r
+\r
+ access_flags = modifiers | /* Modifier.SUPER */ 0x0020;\r
+\r
+ this_class = addClassReference(fullyQualifiedName);\r
+ super_class = addClassReference(superClassName);\r
+ method_info = new MemberTable(0);\r
+ }\r
+\r
+ private void put(ClassFormatOutput out) throws IOException {\r
+\r
+ /* Write out the header */\r
+ out.putU4(VMDescriptor.JAVA_CLASS_FORMAT_MAGIC);\r
+ out.putU2(minor_version);\r
+ out.putU2(major_version);\r
+\r
+ // special case checking that the number of constant\r
+ // pool entries does not exceed the limit of 65535\r
+ // (as it is stored as a U2).\r
+ // Special case to allow somewhat easier debugging\r
+ // of the resulting failure.\r
+ out.putU2("constant_pool", cptEntries.size());\r
+ cptPut(out);\r
+\r
+ out.putU2(access_flags);\r
+ out.putU2(this_class);\r
+ out.putU2(super_class);\r
+\r
+ if (interfaces != null) {\r
+ int ilen = interfaces.length;\r
+ out.putU2(ilen);\r
+ for (int i = 0; i < ilen; i++) {\r
+ out.putU2(interfaces[i]);\r
+ }\r
+ } else {\r
+ out.putU2(0);\r
+ }\r
+\r
+ if (field_info != null) {\r
+ out.putU2(field_info.size());\r
+ field_info.put(out);\r
+ } else {\r
+ out.putU2(0);\r
+ }\r
+\r
+ if (method_info != null) {\r
+ out.putU2(method_info.size());\r
+ method_info.put(out);\r
+ } else {\r
+ out.putU2(0);\r
+ }\r
+\r
+ if (attribute_info != null) {\r
+ out.putU2(attribute_info.size());\r
+ attribute_info.put(out);\r
+ } else {\r
+ out.putU2(0);\r
+ }\r
+\r
+ }\r
+\r
+\r
+ /*\r
+ ** Public methods from ClassHolder.\r
+ */\r
+\r
+ /**\r
+ * Convert the object representation of the class into\r
+ * its class file format.\r
+ * @exception IOException error writing the class\r
+ */\r
+ public ByteArray getFileFormat() throws IOException {\r
+\r
+ int classFileSize = 4 + (10 * 2);\r
+ classFileSize += cptEstimatedSize;\r
+\r
+ if (interfaces != null)\r
+ classFileSize += (interfaces.length * 2);\r
+\r
+ if (field_info != null)\r
+ classFileSize += field_info.classFileSize();\r
+\r
+ if (method_info != null)\r
+ classFileSize += method_info.classFileSize();\r
+\r
+ if (attribute_info != null)\r
+ classFileSize += attribute_info.classFileSize();\r
+\r
+ \r
+ ClassFormatOutput cfo = new ClassFormatOutput(classFileSize + 200);\r
+\r
+ put(cfo);\r
+\r
+ return new ByteArray(cfo.getData(), 0, cfo.size());\r
+\r
+ }\r
+\r
+ /*\r
+ ** Public methods from ClassMember\r
+ */\r
+\r
+ /** @see ClassMember\r
+ */\r
+ public int getModifier() { return access_flags; }\r
+\r
+ /** @see ClassMember\r
+ */\r
+ public String getName() {\r
+ return className(this_class).replace('/', '.');\r
+ }\r
+ /*\r
+ ** Public methods from ClassHolder\r
+ */\r
+\r
+ /** @see ClassHolder#addMember */\r
+ public ClassMember addMember(String simpleName, String descriptor, int modifier)\r
+ {\r
+ if (SanityManager.DEBUG)\r
+ {\r
+ if (descriptor.startsWith("(")) {\r
+ if (method_info != null) {\r
+ if (method_info.find(simpleName, descriptor) != null) {\r
+ SanityManager.THROWASSERT("Method already exists " + simpleName + " " + descriptor);\r
+ }\r
+ }\r
+\r
+ } else {\r
+ if (field_info != null) {\r
+ if (field_info.find(simpleName, descriptor) != null) {\r
+ SanityManager.THROWASSERT("Field already exists " + simpleName + " " + descriptor);\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ CONSTANT_Utf8_info utf = addUtf8Entry(simpleName);\r
+\r
+ int nameIndex = utf.getIndex();\r
+ int descriptorIndex = addUtf8Entry(descriptor).getIndex();\r
+\r
+ ClassMember item = new ClassMember(this, modifier, nameIndex, descriptorIndex);\r
+ MemberTable mt;\r
+ if (descriptor.startsWith("(")) {\r
+ mt = method_info;\r
+ if (mt == null)\r
+ mt = method_info = new MemberTable(0);\r
+\r
+ }\r
+ else {\r
+ mt = field_info;\r
+ if (mt == null)\r
+ mt = field_info = new MemberTable(0);\r
+ }\r
+\r
+ mt.addEntry(item);\r
+ return item;\r
+ }\r
+\r
+ /** @see ClassHolder#addFieldReference */\r
+ public int addFieldReference(String className, String simpleName, String descriptor) {\r
+ return addReference(VMDescriptor.CONSTANT_Fieldref, className, simpleName, descriptor);\r
+ }\r
+\r
+ public int addFieldReference(ClassMember field) {\r
+ return addReference(VMDescriptor.CONSTANT_Fieldref, (ClassMember) field);\r
+ }\r
+\r
+ /** @see ClassHolder#addMethodReference */\r
+ public int addMethodReference(String className, String simpleName, String descriptor, boolean isInterface) {\r
+\r
+ int tag = isInterface ? VMDescriptor.CONSTANT_InterfaceMethodref :\r
+ VMDescriptor.CONSTANT_Methodref;\r
+\r
+ return addReference(tag, className, simpleName, descriptor); \r
+ }\r
+\r
+ private int addReference(int tag, String className, String simpleName, String descriptor) {\r
+\r
+ int classIndex = addClassReference(className);\r
+ int nameTypeIndex = addNameAndType(simpleName, descriptor);\r
+\r
+ return addIndexReference(tag, classIndex, nameTypeIndex);\r
+ }\r
+\r
+ private int addReference(int tag, ClassMember member) {\r
+\r
+ int nameTypeIndex = addIndexReference(VMDescriptor.CONSTANT_NameAndType,\r
+ member.name_index, member.descriptor_index);\r
+\r
+ return addIndexReference(tag, this_class, nameTypeIndex);\r
+ }\r
+\r
+ /** @see ClassHolder#addConstant */\r
+ public int addConstant(String value) {\r
+\r
+ return addString(value);\r
+ }\r
+\r
+ /** @see ClassHolder#addUtf8 */\r
+ public int addUtf8(String value) {\r
+\r
+ return addUtf8Entry(value).getIndex();\r
+ }\r
+\r
+\r
+ /** @see ClassHolder#addConstant */\r
+ public int addConstant(int value) {\r
+ return addDirectEntry(new CONSTANT_Integer_info(value));\r
+ }\r
+\r
+ /** @see ClassHolder#addConstant */\r
+ public int addConstant(float value) {\r
+ return addDirectEntry(new CONSTANT_Float_info(value));\r
+ }\r
+\r
+ /** @see ClassHolder#addConstant */\r
+ public int addConstant(long value) {\r
+ return addDirectEntry(new CONSTANT_Long_info(value));\r
+ }\r
+\r
+ /** @see ClassHolder#addConstant */\r
+ public int addConstant(double value) {\r
+ return addDirectEntry(new CONSTANT_Double_info(value));\r
+ }\r
+\r
+\r
+ /** @see ClassMember\r
+ */\r
+ public int getConstantPoolIndex() { return this_class; }\r
+\r
+ public void addAttribute(String attributeName, ClassFormatOutput info) {\r
+\r
+ if (attribute_info == null)\r
+ attribute_info = new Attributes(1);\r
+\r
+\r
+ CONSTANT_Utf8_info autf = addUtf8Entry(attributeName);\r
+\r
+ int index = autf.getIndex();\r
+\r
+ attribute_info.addEntry(new AttributeEntry(index, info));\r
+ }\r
+\r
+\r
+ public String getSuperClassName() {\r
+ if (super_class == 0)\r
+ return null;\r
+ else\r
+ return className(super_class).replace('/', '.');\r
+ }\r
+\r
+\r
+/*\r
+ public ClassMember getMemberReference(String fullyQualifiedClassName, String simpleName, String descriptor) {\r
+\r
+ int classIndex;\r
+\r
+ if (fullyQualifiedClassName == null)\r
+ classIndex = this_class;\r
+ else\r
+ classIndex = constantPool.findClass(fullyQualifiedClassName);\r
+\r
+ if (classIndex < 0)\r
+ return null;\r
+\r
+ int nameAndTypeIndex = constantPool.findNameAndType(simpleName, descriptor);\r
+ if (nameAndTypeIndex < 0)\r
+ return null;\r
+\r
+ return constantPool.findReference(classIndex, nameAndTypeIndex);\r
+ }\r
+*/\r
+ /*\r
+ ** Public methods from ClassRead\r
+ */\r
+\r
+\r
+\r
+ /*\r
+ ** Implementation specific methods.\r
+ */\r
+\r
+ /*\r
+ ** Methods related to Constant Pool Table\r
+ */\r
+ /**\r
+ Generic add entry to constant pool. Includes the logic\r
+ for an entry to occupy more than one slot (e.g. long).\r
+\r
+ @return The number of slots occupied by the entry.\r
+.\r
+ */\r
+ protected int addEntry(Object key, ConstantPoolEntry item) {\r
+\r
+ item.setIndex(cptEntries.size());\r
+ if (key != null)\r
+ cptHashTable.put(key, item);\r
+ cptEntries.addElement(item);\r
+\r
+ cptEstimatedSize += item.classFileSize();\r
+\r
+ if (item.doubleSlot()) {\r
+ cptEntries.addElement(null);\r
+ return 2;\r
+ } else {\r
+ return 1;\r
+ }\r
+ }\r
+ \r
+ /**\r
+ Add an entry, but only if it doesn't exist.\r
+\r
+ @return the constant pool index of the added\r
+ or existing item.\r
+ */\r
+ private int addDirectEntry(ConstantPoolEntry item) {\r
+ ConstantPoolEntry existingItem = findMatchingEntry(item);\r
+ if (existingItem != null) {\r
+ item = existingItem;\r
+ //foundCount++;\r
+ }\r
+ else {\r
+ addEntry(item.getKey(), item);\r
+ }\r
+ return item.getIndex();\r
+ }\r
+\r
+ /**\r
+ Add an index reference.\r
+ */\r
+ private int addIndexReference(int tag, int i1, int i2) {\r
+\r
+ // search for the item using the pre-allocated object \r
+ searchIndex.set(tag, i1, i2);\r
+\r
+ ConstantPoolEntry item = findMatchingEntry(searchIndex);\r
+\r
+ if (item == null) {\r
+ item = new CONSTANT_Index_info(tag, i1, i2);\r
+ addEntry(item.getKey(), item);\r
+ }\r
+\r
+ return item.getIndex();\r
+ }\r
+\r
+ /**\r
+ Add a class entry to the pool.\r
+ */\r
+ public int addClassReference(String fullyQualifiedName) {\r
+ if (ClassHolder.isExternalClassName(fullyQualifiedName)) {\r
+ fullyQualifiedName = ClassHolder.convertToInternalClassName(fullyQualifiedName);\r
+ // System.out.println("addClassReference " + fullyQualifiedName);\r
+ }\r
+\r
+ int name_index = addUtf8Entry(fullyQualifiedName).getIndex();\r
+\r
+ return addIndexReference(VMDescriptor.CONSTANT_Class, name_index, 0);\r
+ }\r
+\r
+ /**\r
+ Add a name and type entry\r
+ */\r
+ private int addNameAndType(String name, String descriptor) {\r
+ int nameIndex = addUtf8Entry(name).getIndex();\r
+\r
+ int descriptorIndex = addUtf8Entry(descriptor).getIndex();\r
+\r
+ return addIndexReference(VMDescriptor.CONSTANT_NameAndType, nameIndex, descriptorIndex);\r
+ }\r
+\r
+ /**\r
+ Add a UTF8 into the pool and return the index to it.\r
+ */\r
+ private CONSTANT_Utf8_info addUtf8Entry(String value) {\r
+\r
+ CONSTANT_Utf8_info item = (CONSTANT_Utf8_info) findMatchingEntry(value);\r
+\r
+ if (item == null) {\r
+\r
+ item = new CONSTANT_Utf8_info(value);\r
+ addEntry(value, item);\r
+ }\r
+ return item;\r
+ }\r
+ /**\r
+ Add an extra UTF8 into the pool \r
+ */\r
+ private CONSTANT_Utf8_info addExtraUtf8(String value) {\r
+\r
+ CONSTANT_Utf8_info item = new CONSTANT_Utf8_info(value);\r
+ addEntry(null, item);\r
+\r
+ return item;\r
+ }\r
+\r
+ /**\r
+ Add a string entry\r
+ */\r
+ private int addString(String value) {\r
+ CONSTANT_Utf8_info sutf = addUtf8Entry(value);\r
+ int valueIndex = sutf.setAsString();\r
+ if (valueIndex == 0) {\r
+ // string is already being used as code\r
+ valueIndex = addExtraUtf8(value).getIndex();\r
+ sutf.setAlternative(valueIndex);\r
+ }\r
+\r
+ return addIndexReference(VMDescriptor.CONSTANT_String, valueIndex, 0);\r
+ }\r
+\r
+ /**\r
+ Add a string entry\r
+ */\r
+ private int addCodeUtf8(String value) {\r
+ CONSTANT_Utf8_info sutf = addUtf8Entry(value);\r
+ int index = sutf.setAsCode();\r
+ if (index == 0) {\r
+ // code string is already being used as string\r
+ CONSTANT_Utf8_info eutf = addExtraUtf8(value);\r
+ eutf.setAsCode(); // ensure the replace will happen\r
+ index = eutf.getIndex();\r
+ sutf.setAlternative(index);\r
+ }\r
+\r
+ return index;\r
+ }\r
+ protected void cptPut(ClassFormatOutput out) throws IOException {\r
+\r
+ for (Enumeration e = cptEntries.elements(); e.hasMoreElements(); ) {\r
+ ConstantPoolEntry item = (ConstantPoolEntry) e.nextElement();\r
+ if (item == null) {\r
+ continue;\r
+ }\r
+\r
+ item.put(out);\r
+ }\r
+ }\r
+\r
+ /*\r
+ ** Methods to convert indexes to constant pool entries and vice-versa.\r
+ */\r
+\r
+ public ConstantPoolEntry getEntry(int index) {\r
+ return (ConstantPoolEntry) cptEntries.elementAt(index);\r
+ }\r
+\r
+ /**\r
+ Return the class name for an index to a CONSTANT_Class_info.\r
+ */\r
+\r
+ protected String className(int classIndex) {\r
+ CONSTANT_Index_info ci = (CONSTANT_Index_info) getEntry(classIndex);\r
+\r
+ return nameIndexToString(ci.getI1()).replace('/', '.');\r
+\r
+ }\r
+\r
+ /*\r
+ ** Methods to find specific types of constant pool entries.\r
+ In these methods we try to avoid using the ConstantPoolEntry.matchValue()\r
+ as that requires creating a new object for the search. The matchValue()\r
+ call is really intended for when objects are being added to the constant pool.\r
+ */\r
+\r
+ /**\r
+ Return the index of a UTF entry or -1 if it doesn't exist.\r
+ */\r
+ int findUtf8(String value) {\r
+\r
+ ConstantPoolEntry item = findMatchingEntry(value);\r
+ if (item == null)\r
+ return -1;\r
+\r
+ return item.getIndex();\r
+ }\r
+\r
+ /**\r
+ Find a class descriptor (section 4.4.1) and return its\r
+ index, returns -1 if not found.\r
+ */\r
+ public int findClass(String fullyQualifiedName) {\r
+ String internalName = ClassHolder.convertToInternalClassName(fullyQualifiedName);\r
+ int utf_index = findUtf8(internalName);\r
+ if (utf_index < 0)\r
+ return -1;\r
+\r
+ return findIndexIndex(VMDescriptor.CONSTANT_Class,\r
+ utf_index, 0);\r
+ }\r
+\r
+\r
+ /**\r
+ Find a name and type descriptor (section 4.4.6) and\r
+ return it's index. \r
+ <p>\r
+ returns -1 if not found.\r
+ */\r
+ public int findNameAndType(String name, String descriptor) {\r
+\r
+ int name_index = findUtf8(name);\r
+ if (name_index < 0)\r
+ return -1;\r
+ int descriptor_index = findUtf8(descriptor);\r
+ if (descriptor_index < 0)\r
+ return -1;\r
+\r
+ return findIndexIndex(VMDescriptor.CONSTANT_NameAndType,\r
+ name_index, descriptor_index);\r
+ }\r
+/*\r
+ public ClassMember findReference(int classIndex, int nameAndTypeIndex) {\r
+\r
+ CONSTANT_Index_info item = findIndexEntry(VMDescriptor.CONSTANT_Methodref,\r
+ classIndex, nameAndTypeIndex);\r
+\r
+ if (item == null) {\r
+\r
+ item = findIndexEntry(VMDescriptor.CONSTANT_InterfaceMethodref,\r
+ classIndex, nameAndTypeIndex);\r
+\r
+ if (item == null) {\r
+ item = findIndexEntry(VMDescriptor.CONSTANT_Fieldref,\r
+ classIndex, nameAndTypeIndex);\r
+\r
+ if (item == null)\r
+ return null;\r
+\r
+ }\r
+ }\r
+\r
+ return new ReferenceMember(this, item);\r
+ }\r
+*/\r
+ protected CONSTANT_Index_info findIndexEntry(int tag, int i1, int i2) {\r
+ // search for the item using the pre-allocated object \r
+ searchIndex.set(tag, i1, i2);\r
+\r
+ return (CONSTANT_Index_info) findMatchingEntry(searchIndex);\r
+ }\r
+\r
+ protected int findIndexIndex(int tag, int i1, int i2) {\r
+ CONSTANT_Index_info item = findIndexEntry(tag, i1, i2);\r
+ if (item == null)\r
+ return -1;\r
+\r
+ return item.getIndex();\r
+ }\r
+\r
+ protected ConstantPoolEntry findMatchingEntry(Object key) {\r
+ return (ConstantPoolEntry) cptHashTable.get(key);\r
+ }\r
+\r
+ /** get a string (UTF) given a name_index into the constant pool\r
+ */\r
+ String nameIndexToString(int index) {\r
+\r
+ return getEntry(index).toString();\r
+ }\r
+\r
+ /** get the class name of a Class given the index of its CONSTANT_Class_info\r
+ entry in the Constant Pool.\r
+ */\r
+\r
+ protected String getClassName(int index) {\r
+\r
+ if (index == 0)\r
+ return ""; // must be the super class of java.lang.Object, ie. nothing.\r
+\r
+ return nameIndexToString(getEntry(index).getI1());\r
+ }\r
+\r
+ /*\r
+ * Determine whether the class descriptor string is \r
+ * in external format or not. Assumes that to be in external\r
+ * format means it must have a '.' or end in an ']'.\r
+ * \r
+ * @param className the name of the class to check\r
+ *\r
+ * @return true/false\r
+ */\r
+ public static boolean isExternalClassName(String className)\r
+ {\r
+ int len;\r
+ if (className.indexOf('.') != -1)\r
+ {\r
+ return true;\r
+ }\r
+ else if ((len = className.length()) == 0)\r
+ { \r
+ return false;\r
+ }\r
+ return (className.charAt(len - 1) == ']');\r
+ }\r
+\r
+ /*\r
+ * Convert a class name to the internal VM class name format.\r
+ See sections 4.3.2, 4.4.1 of the vm spec.\r
+ * The normal leading 'L' and trailing ';' are left\r
+ * off of objects. This is intended primarily for\r
+ * the class manager.\r
+ * <p>\r
+ * An example of a conversion would be java.lang.Double[]\r
+ * to "[Ljava/lang/Double;".\r
+ <BR>\r
+ java.lang.Double would be converted to "java/lang/Double"\r
+\r
+ <BR>\r
+ Note that for array types the result of convertToInternalClassName()\r
+ and convertToInternalDescriptor() are identical.\r
+\r
+ *\r
+ * @param the external name (cannot be null)\r
+ *\r
+ * @return the internal string\r
+ */\r
+ public static String convertToInternalClassName(String externalName)\r
+ {\r
+ return convertToInternal(externalName, false);\r
+ }\r
+\r
+ /*\r
+ * Convert a class name to internal JVM descriptor format.\r
+ See sections 4.3.2 of the vm spec.\r
+ * <p>\r
+ * An example of a conversion would be "java.lang.Double[]"\r
+ * to "[Ljava/lang/Double;".\r
+ *\r
+ <BR>\r
+ java.lang.Double would be converted to "Ljava/lang/Double;"\r
+\r
+ <BR>\r
+ Note that for array types the result of convertToInternalClassName()\r
+ and convertToInternalDescriptor() are identical.\r
+\r
+ * @param the external name (cannot be null)\r
+ *\r
+ * @return the internal string\r
+ */\r
+ public static String convertToInternalDescriptor(String externalName)\r
+ {\r
+ return convertToInternal(externalName, true);\r
+ }\r
+\r
+ /*\r
+ ** Workhorse method. Convert to internal format.\r
+\r
+ @param descriptor True if converting to descriptor format, false if\r
+ converting to class name format.\r
+ **\r
+ ** Lifted from BCClass.java. \r
+ **\r
+ ** Returns the result string.\r
+ */\r
+ private static String convertToInternal(String externalName, boolean descriptor)\r
+ {\r
+ if (SanityManager.DEBUG)\r
+ {\r
+ SanityManager.ASSERT(externalName != null, "unexpected null");\r
+ }\r
+\r
+ int len = externalName.length();\r
+\r
+ String internalName; \r
+ String retVal = null; \r
+ int origLen = len;\r
+ int arity = 0;\r
+\r
+ // first walk through all array-ness\r
+ if (externalName.charAt(len-1) == ']')\r
+ {\r
+ while (len > 0\r
+ && externalName.charAt(len-1) == ']'\r
+ && externalName.charAt(len-2) == '[') \r
+ {\r
+ len -= 2;\r
+ arity++;\r
+ }\r
+ }\r
+ if (SanityManager.DEBUG) {\r
+ SanityManager.ASSERT(len > 0);\r
+ }\r
+\r
+ internalName = (origLen == len)? \r
+ externalName \r
+ : externalName.substring(0,len);\r
+\r
+ // then check for primitive types ... \r
+ // in length by expected frequency order\r
+\r
+ switch (len) {\r
+ case 7 :\r
+ if ("boolean".equals(internalName)) {\r
+ retVal = makeDesc(VMDescriptor.C_BOOLEAN, arity);\r
+ }\r
+ break;\r
+ case 4 :\r
+ if ("void".equals(internalName)) {\r
+ retVal = makeDesc(VMDescriptor.C_VOID, arity);\r
+ }\r
+ else if ("long".equals(internalName)) {\r
+ retVal = makeDesc(VMDescriptor.C_LONG, arity);\r
+ }\r
+ else if ("byte".equals(internalName)) {\r
+ retVal = makeDesc(VMDescriptor.C_BYTE, arity);\r
+ }\r
+ else if ("char".equals(internalName)) {\r
+ retVal = makeDesc(VMDescriptor.C_CHAR, arity);\r
+ }\r
+ break;\r
+ case 3 :\r
+ if ("int".equals(internalName)) {\r
+ retVal = makeDesc(VMDescriptor.C_INT, arity);\r
+ }\r
+ break;\r
+ case 6 :\r
+ if ("double".equals(internalName)) {\r
+ retVal = makeDesc(VMDescriptor.C_DOUBLE, arity);\r
+ }\r
+ break;\r
+ case 5 :\r
+ if ("short".equals(internalName)) {\r
+ retVal = makeDesc(VMDescriptor.C_SHORT, arity);\r
+ }\r
+ else if ("float".equals(internalName)) {\r
+ retVal = makeDesc(VMDescriptor.C_FLOAT, arity);\r
+ }\r
+ break;\r
+ }\r
+\r
+ // then it must be a Java class\r
+ if (retVal == null)\r
+ retVal = makeDesc(internalName, arity, descriptor);\r
+\r
+ return retVal;\r
+ }\r
+\r
+ /**\r
+ A helper to build a type description based on a built-in type\r
+ and an array arity.\r
+ */\r
+ static private String makeDesc (char builtin, int arity) {\r
+ if (arity == 0)\r
+ switch (builtin) {\r
+ case VMDescriptor.C_BYTE : return VMDescriptor.BYTE;\r
+ case VMDescriptor.C_CHAR : return VMDescriptor.CHAR;\r
+ case VMDescriptor.C_DOUBLE : return VMDescriptor.DOUBLE;\r
+ case VMDescriptor.C_FLOAT : return VMDescriptor.FLOAT;\r
+ case VMDescriptor.C_INT : return VMDescriptor.INT;\r
+ case VMDescriptor.C_LONG : return VMDescriptor.LONG;\r
+ case VMDescriptor.C_SHORT : return VMDescriptor.SHORT;\r
+ case VMDescriptor.C_BOOLEAN : return VMDescriptor.BOOLEAN;\r
+ case VMDescriptor.C_VOID : return VMDescriptor.VOID;\r
+ default: \r
+ if (SanityManager.DEBUG)\r
+ SanityManager.THROWASSERT("No type match");\r
+ return null;\r
+ }\r
+ else {\r
+ StringBuffer desc = new StringBuffer(arity+3);\r
+\r
+ for (int i=0;i<arity;i++)\r
+ desc.append(VMDescriptor.C_ARRAY);\r
+\r
+ desc.append(ClassHolder.makeDesc(builtin, 0));\r
+\r
+ return desc.toString();\r
+ }\r
+ }\r
+\r
+ /**\r
+ A helper to build a type description based on a Java class\r
+ and an array arity.\r
+\r
+ If descriptor is true create a descriptor according to\r
+ section 4.3.2 of the vm spec. If false create a class name\r
+ according to sections 4.3.2 and 4.4.1 of the vm spec.\r
+ \r
+ */\r
+ static private String makeDesc (String className, int arity, boolean descriptor) {\r
+\r
+ if (!descriptor && (arity == 0)) {\r
+ return className.replace('.','/');\r
+ }\r
+\r
+ StringBuffer desc = new StringBuffer(arity+2+className.length());\r
+\r
+ for (int i=0;i<arity;i++)\r
+ desc.append(VMDescriptor.C_ARRAY);\r
+\r
+ desc.append(VMDescriptor.C_CLASS);\r
+\r
+ desc.append(className.replace('.','/'));\r
+\r
+ desc.append(VMDescriptor.C_ENDCLASS);\r
+\r
+ return desc.toString();\r
+ }\r
+\r
+\r
+}\r