I’ve been working on a custom class loader that does the instrumentation required for the thread checker on the fly. I’ve got most of it working now, even though I ran into a bunch of weird bugs that had me confused for several hours: I was using incorrectly formatted class names, names in the format “Lsome/package/name/MyClass$InnerClass;"
, as they are used in descriptors and annotations for class constant pool info items that expect class names of the format "some/package/name/MyClass$InnerClass"
. For some reason, this ran without any “Illegal class name” ClassNotFoundExceptions
when I instrumented everything offline, but when I did the instrumentation on the fly, the exception was thrown.
The problem I’m facing now concerns auto-generated compound annotations, and also only in the on-the-fly version: I’m getting InvocationTargetExceptions
when the auto-generated predicate method is trying to make a call to a member predicate method that is in a private or package-private class.
java.lang.IllegalAccessError: tried to access class sample.threadCheck.predicate.PrintPrimitive from class auto.sample.threadCheck.predicate.AndPrintStringsPred
Here, auto.sample.threadCheck.predicate.AndPrintStringsPred
is the automatically generated class with the predicate for a @Combine
-style annotation. sample.threadCheck.predicate.PrintPrimitive
is a package-private class that contains the predicate method for the PrintStringAnnotation
, which is a member of AndPrintStringsPred
.
Right now, I see two ways around this: Either I use some reflection magic and allow access to private entities, or I change the placement and naming of auto-generated classes. Allowing access to private entities, if not done carefully, might alter the behavior of the program that is running. I have to check if I can somehow enable access just when I need it and disable it afterwards. That might be the easiest way.
The other way, of course, would be to generate the predicate classes so that they do have access to the private classes they need. However, I don’t believe that’s possible in all cases. What if an auto-generated class needs to refer to two package-private classes that reside in two different packages? I think I’ll go with the former route, even though I don’t like the prospect of enabling and disabling reflection features frequently.
In general, though, the good news is that the custom class loader is very easy to use. It’s almost the same as running something using the java
command: Right now, the class to use is edu.rice.cunit.CUnitRun
, which can do on-the-fly instrumentation for any kind of instrumentation strategy, but I’ll probably wrap that in a dedicated class, perhaps something like edu.rice.cunit.TCRun
.
Instead of writing java MyProg
, right now I have to write
java edu.rice.cs.cunit.CUnitRun -i edu.rice.cs.cunit.instrumentors.threadCheck.CompoundThreadCheckStrategy MyProg
This looks quite cumbersome, but it’s actually pretty simple. CUnitRun
is basically a replacement for javac
, the -i
argument with the following class name specifies the instrumentation strategy to run, in this case the Thread Checker strategy, and the normal javac
arguments follow after that. There are a few more flags for debugging and finer-grained control, but they don’t really matter right now. With a dedicated class to run the Thread Checker instrumentation on-the-fly, the command will boil down to this:
java edu.rice.cs.cunit.TCRun MyProg
Simple enough, I think.