![]() |
|||
![]() ![]() |
![]() |
|
![]() |
Constant poolThe constant pool is a data structure that stores all the constants in a program, not just literals like 1.0 or 72, but also class structures, method references, and the names and types of variables. The disassembler needs to make frequent reference back to this data structure when parsing later parts of the file. Many other entries in the .class file simply refer back to constants stored in the constant pool. It is therefore necessary to create a data structure to hold the constants for later reference. The largest difficulty in this endeavor is that the constant pool has to hold values of 11 different types. To make matters worse, six of those types are reference types and five are primitive types. Because this is relatively complex, Im going to push all the details into a new class called ConstantPool. The Disassembler class will simply call the ConstantPool() constructor, as shown in Listing 4-10. The ConstantPool() constructor will read the data out of theInput and parse it, and a new ConstantPool object will be stored in the field thePool. Listing 4-10 The ConstantPool() constructor ConstantPool thePool; void readConstantPool() throws IOException { thePool = new ConstantPool(theInput); } The exact size of the constant pool depends on whats inside it. The first two bytes of this part of the file are an unsigned short specifying the number of entries in the constant pool. This number must be greater than zero. The first constant pool entry is reserved for the virtual machines use. Therefore, there is actually one less than this number of actual entries to be read. However, entries of different types can have different sizes. Listing 4-11 is the ConstantPool class. This class does two things: first, it reads the constant pool from the file; second, it responds to requests for items from the constant pool. The ConstantPool class is implemented as an array of PoolEntry objects. Listing 4-12 is the PoolEntry class. A PoolEntry object can hold one item that has one of the 11 different types and classes that can be stored in the constant pool. The ConstantPool constructor first reads two bytes from the InputStream as an unsigned short. This specifies the number of entries in the ConstantPool so that it can decide how large to make the PoolEntry array. Then, it passes InputStream to the PoolEntry() constructor enough times to fill the array. The PoolEntry() constructor determines the type of that entry in the pool and reads the right number of bytes for that type. To read a particular entry from the constant pool, you call the properly typed read method of ConstantPool for example, readDouble(int i) to get a double constant from the pool. These methods retrieve the right PoolEntry from the array and then call that entrys matching read method. All information about the type of a PoolEntry is stored in the PoolEntry itself. The user, however, will generally need to know the type of the entry being requested. If the user requests the wrong type from a PoolEntry, then the PoolEntry will throw a ClassFormatError.
Listing 4-11 The ConstantPool class import java.io.*; public class ConstantPool { PoolEntry[] thePool; public ConstantPool(DataInputStream dis) throws IOException { int length = dis.readUnsignedShort(); thePool = new PoolEntry[length]; for (int i = 1; i < length; i++) { thePool[i] = new PoolEntry(dis); // Doubles and longs take two pool entries // see Java VM Spec., p. 98 if (thePool[i].tag == PoolEntry.cDouble || thePool[i].tag == PoolEntry.cLong) i++; } } public PoolEntry read(int i) { return thePool[i]; } public String readUTF8(int i) { return thePool[i].readUTF8(); } public int readInteger(int i) { return thePool[i].readInteger(); } public float readFloat(int i) { return thePool[i].readFloat(); } public double readDouble(int i) { return thePool[i].readDouble(); } public ClassInfo readClassInfo(int i) { return thePool[i].readClassInfo(); } public RefInfo readMethodRef(int i) { return thePool[i].readMethodRef(); } public RefInfo readInterfaceMethodRef(int i) { return thePool[i].readInterfaceMethodRef(); } public NameAndType readNameAndType(int i) { return thePool[i].readNameAndType(); } public int howMany() { return thePool.length; } public String toString() { String result = ; for (int i = 1; i < thePool.length; i++) { result += i + : + thePool[i].toString() + \n; // Doubles and longs take two pool entries // see Java VM Spec., p. 98 if (thePool[i].tag == PoolEntry.cDouble || thePool[i].tag == PoolEntry.cLong) i++; } return result; } }
|
![]() |
|