JOIE transformers operate on ClassInfo objects, which encapsulate and export all of the information present in class files. The JOIE ClassLoader creates a ClassInfo object for the class before invoking the first transformer, then passes the ClassInfo to each registered transformer in sequence. After the last transformer completes, the ClassLoader converts the ClassInfo into a transformed classfile byte array in memory, and submits it to the JVM for verification.
To improve performance, the JOIE toolkit methods parse the elements of the target classfile lazily as they are requested by transformers. For example, if a transformer simply adds a new interface to the list of interfaces implemented by the class, then ClassInfo need not parse the list of fields, methods, or bytecodes. Since each ClassInfo instance preserves parsing state across transformers, each element of a transformed class is parsed at most once.
Java classfiles retain a great deal of symbolic information in a data structure known as the Constant Pool, including variable-length symbol entries for all methods, fields, and constants defined or referenced by the class. Entries in the Constant Pool may address other entries by index. For example, an entry for a method Banana.peel() contains the index of the entry for class Banana and the index of an entry holding the name and type of the method. The entry for class Banana in turn contains the index for the UTF-8-encoded string ``Banana.'' The name and type are also stored as indices that point to encoded strings for the name (``peel'' in our example) and the descriptor, which encodes parameter and return types.
All references in instructions -- including field accesses and method invocations -- are represented as indices pointing to symbolic names stored in the Constant Pool. The JVM resolves external references by symbolic name as the program executes.
This structure allows the JOIE toolkit to implement a wide range of load-time class modifications easily. In particular, it is rarely necessary to update classes that reference the transformed class, since all references into the target class are resolved by symbolic lookup in their own Constant Pool. Moreover, many class modifications can be implemented simply by adding or manipulating individual entries in the Constant Pool. In particular, it is unnecessary to modify the bytecode instructions in the target class unless the transformer explicitly requests it. A change to the Constant Pool affects method instructions only if it changes the index of an entry in the Constant Pool. Fortunately, there are no ordering constraints on the Constant Pool, so any new entries can be appended rather than inserted in the middle, preserving the indices of existing entries. Unreferenced entries are simply left in place.
As the JOIE toolkit parses the Constant Pool, it creates a list for each type of entry, storing each symbol value and its index. This allows us to more quickly add new entries without duplication. For example, to insert a new entry for a Field we first search the list of field entries to ensure that an entry with the requested class, name, and type is not already present. If not, we construct a new field entry, and must then search for or create appropriate class, name, and type entries.