-
Notifications
You must be signed in to change notification settings - Fork 13
Overview
Download out ICSE presentation here as Keynote or PDF file. You may use it under the Creative Commons “Attribution-ShareAlike” license.
The following figure gives an overview of the architecture of TamiFlex, our tool
suite for taming reflection. On the top left, we show a program that uses
(potentially custom) class loaders to load classes from arbitrary locations
(the cloud), or even to generate classes on the fly. The program may further
call methods such as Class.forName()
, Constructor.newInstance()
or
Method.invoke()
to construct objects or invoke methods through reflection.
Let us now assume that the program executes with our first instrumentation
agent installed: the Play-out Agent, which
the figure shows below the program. In this agent, the Tracer, a class-file transformer, instruments the
classes Class
, Method
and Constructor
so that calls to
methods such as Class.forName()
generate entries in a log file (shown on
the bottom left). The agent further comprises a Dumper component, which writes
all classes loaded by the program, including classes that the
program's class loaders may have generated on the fly, to a local repository. Certain class loaders
assign randomized names to such classes. To be able to re-identify such classes
across multiple runs, the Dumper renames these classes using a hash code over
the contents of the class. The Dumper communicates with a Hasher component to
obtain these hash codes.
Executing a program with the Play-out Agent enabled will result in an repository containing a reflection log file and all classes that the program loaded during the observed run. To obtain a reasonably complete log file and set of classes, users can run the program multiple times. The agent will then automatically update the log, appending information about reflective calls that were not previously observed, and dump additional classes that had not been loaded on previous runs. Users can repeat this process until reaching a fixed point.
The user has now two options to further proceed with the classes gathered by the Play-Out Agent:
- use a specialized, TamiFlex-aware static analysis (shown in gray), or
- use the Booster in combination with virtually any static-analysis tool for Java bytecode.
Users can feed the log file and the dumped classes into into some TamiFlex-aware static-analysis tool to conduct static analyses, and to transform, e.g., optimize or instrument, the code. We use Soot with Spark for this purpose. Running Soot results in a set of transformed class files that we show on the bottom right of the figure.
Alternatively, users can use the Booster to "enrich" the program. Boosting will prepare the program for static analysis by "materializing" reflective method calls into normal Java method calls in the program's bytecode. (More information here.) This will allow virtually any static analysis tool to treat all recorded method calls just as normal method calls, hence improving the soundness of those analyses.
The Booster is part of TamiFlex since version 1.1.
The right-hand side of the figure shows what happens when the user runs the program with the second agent, the Play-in Agent, enabled. Whenever the original program is about to load a class c, a Replacer within the agent tries to retrieve the offline-transformed version of c from the local repository. For classes that bear a randomly generated class name, the agent asks the Hasher component compute the hash code for the class. The Replacer then looks for the offline-transformed class under the same normalized, i.e., hash-code based, name that the Dumper would have used to store the class. If the Replacer finds a class in the repository, replaces the originally loaded (or generated) class with this loaded class on the fly. Otherwise, i.e., if the Replacer cannot find an appropriate class file, for instance because no such class was loaded on previous runs, the Replacer executes no replacement. This means that in this case the program will instantiate the class that the class loader originally loaded from ``the cloud''. Through a command-line option to the Play-in Agent, users can opt to have a warning message issued when such a situation occurs.
Note the flexibility of this design; TamiFlex works with any Java 6-compatible virtual
machine that supports re-transforming classes through the
java.lang.instrument
application programming interface. Through this interface, our
agents are able to write out and replace classes that the program generates
at runtime. With the aid of our Hasher component, this even works in cases where the
program generates classes with randomized names. Further, we pose no special
restrictions on the static-analysis component (here Soot/Spark), except that
the analysis must be able to load class files from disk, to write class files to
disk and to correctly interpret the reflection log file that TamiFlex generates.