I’ve already mentioned that the JPDA monitor reads and clears a list mainainted in the slave. Reading isn’t the problem, but clearing is a bit tricky. If the monitor just had to read, then hardly any synchronization were necessary (well, I’d have to write my own version of
ArrayList. I looked at its source and noticed that
ArrayList increments the size first, then puts the entry in. It would be cleaner the other way around).
The monitor needs to clear the list too, though, and that is a write access. This is a recipe for a race condition. If the monitor clears the list after the slave has determined where it needs to put the new event but before the slave has actually put the event into the list, the slave will experience a
NullPointerException (the monitor resets the list to null. I couldn’t find a way to create a new
It is somewhat ironic: A synchronization bug, in a program that is supposed to fight synchronization bugs.
I’ve devised two strategies to prevent this problem:
- Whenever the slave adds an event, it grabs a lock (using a synchronized method). The monitor can check if that lock is held by a thread and postpone checking the list until the thread has finished adding the event. This can somewhat easily be done using a “method exit event” from JPDA. The advantage is low memory use and an immediate update right when the slave is done. I’m afraid that enabling and disabling this JPDA event will be too slow.
- Another strategy is to just not clear the list if the lock is held. In that case, the monitor remembers how many entries in the list it has already seen. The next time around, only new events will be processed. Eventually (hopefully?), the lock will not be held, and the list can be cleared. The advantage here is no added cost, but at least theoretically, the list can grow without bound.
Of course, both methods can be combined, with 1. providing a low-memory fall-back for 2. Right now I have implemented option 1, and at least in simple tests it seems fast enough, so I’m not writing 2. yet.
However, I’d like to test this on a larger program, and that large program is DrJava, of course. To efficiently do that, I’ll need to dust off and modify the custom class loader again, so that’s what I’ll probably do next.
Running a program will mean running the monitor with the slave as a parameter. The boot classpath for the slave also has to be changed so that it includes the instrumented runtime files and several monitor classes (the
SyncPointRecorder class, for example). The monitor then loads the slave, and the class loader instruments all user classes.
Since I don’t want to instrument classes again that have already been instrumented (that would wreak havoc;
foo<Wrapper> methods would call themselves, etc.), I’ll have to figure out how to distinguish user classes from runtime classes, or better: instrumented classes from uninstrumented ones. Maybe I can use Java annotations for that?