Dependency Fixpoint

Now that I’m adding the InstrumentingClassLoader to the runtime to load and instrument classes on the fly, additional classes need to go into the rt.jar file, and it quickly becomes confusing which ones to include. The custom class loader references nearly the entire runtime portion of the project, but not the JPDA monitor.

I still didn’t want to draw the line by hand and risk a mistake. Well, I did and failed. Practically, all classes that get referenced in the class I am running need to be available in rt.jar, and all the classes that get referenced in them, and so on. Conceptually, this is the least class dependency fixpoint.

Now I wrote a tool, edu.rice.cs.cunit.DependencyFixPoint, that lists all the classes in that fixpoint, starting with any number of classes. The files can be output as file names and piped into jar to create an archive of just the files necessary. Now everything is automated and exactly the right files get added to the runtime.

I’ve also fixed a bug related to the Instrumentation attribute. Until tonight, I never had the case where the string “Instrumentation” was already present in the class file, and it worked because a new item was added to the constant pool. Tonight, I instrumented InstrumentingClassLoader.class, which already contains the string “Instrumentation”, so it is supposed to reuse it. That’s where it failed. Fixed.

And I’ve noticed that I actually don’t need to include the monitor.jar file (which I now renamed cunitrt.jar) separately on the boot class path. I merge it into the rt.jar already.

Update

I just found another problem. The way I changed the automation, now all the files added to the rt.jar got instrumented. Of course, SyncPointRecorder still contains that little comment “do not instrument”, which now got ignored. Infinite recursion generally isn’t a good thing.

Now you can add the @DoNotInstrument annotation to a class to prevent it from getting instrumented. Both the offline FileInstrumenter and the on the fly InstrumentingClassLoader obey the annotation.

Share
Posted in Concurrent Unit Testing | Leave a comment

Print This Post Print This Post  

Sneaky Sun

Again, since I’m stuck, I looked for different work that needed to be done and found the InstrumentingClassLoader. For some reason, it wouldn’t quite work anymore. It said something about an illegal method name sleep<Wrapper>. I checked the file, everything seemed as always. In fact, when I instrumented the file offline, everything worked to the extent it was working before.

I’ve been tinkering with the class loader in general, making several other improvements, and don’t have it working yet, but it seems like Sun changed the behavior of java.lang.ClassLoader in one of the Java 1.5.0 updates (currently, I have the 1.5.0_04 version installed). Before, ClassLoader would accept method names that include characters like < and >, even though they couldn’t be generated by Java programs. That’s exactly why I chose them. If classes are not loaded and instrumented on the fly, Java still has this behavior. But if a custom class loader is used now, these method names are being rejected.

I’ve changed my naming scheme to $$$Wrapper$$$ and $$$Old$$$. The triple-$ is to avoid problems with James Sasitorn’s NexGen. I’ll still have to have a chat with him to make sure there won’t be any clashes. Testing both custom class loaders together will be interesting too.

Share
Posted in Concurrent Unit Testing | Leave a comment

Print This Post Print This Post  

Instrumentation Attribute

Because I was stuck with the hanging slave, I took a look at the InstrumentingClassLoader again. It’s a custom class loader that rewrites class files as they are loaded during runtime.

I abandoned working on that a while ago when I ran into problems with mutually recursive references. Somehow, my class loader got confused when it was loading a class A that referenced a class B that, directly or indirectly, referenced A again… Instead, I resorted to offline instrumentation using FileInstrumentor. That makes more sense with the giant rt.jar anyway. There’s no reason to instrument those classes all over again.

I haven’t tested it a lot yet, but at least it seems to integrate well with the launcher and the JPDA monitor. Now I have a lot more files that should not be instrumented, though, that need to be included in the bootclasspath and loaded.

I felt like adding a string mask to exclude them wasn’t flexible enough, so I introduced a custom attribute called “Instrumentation”. If a file has been instrumented already, that attribute is added to the class file. The attribute data is a string of the instrumentor class names, separated by semicolon. Currently, the following string is generated:

"edu.rice.cs.cunit.instrumentors.MethodHashTableInstrumentationStrategy;
edu.rice.cs.cunit.instrumentors.ThreadInstrumentationStrategy;
edu.rice.cs.cunit.instrumentors.SleepYieldCallInstrumentationStrategy;
edu.rice.cs.cunit.instrumentors.SleepYieldInstrumentationStrategy;
edu.rice.cs.cunit.instrumentors.ObjectCallInstrumentationStrategy;
edu.rice.cs.cunit.instrumentors.ObjectInstrumentationStrategy;
edu.rice.cs.cunit.instrumentors.SynchronizedMethodToBlockInstrumentationStrategy;
edu.rice.cs.cunit.instrumentors.SynchronizedBlockInstrumentationStrategy"

If a class just shouldn’t be instrumented, then that attribute is added with an empty string. A class is only instrumented if the “Instrumentation” attribute is not present yet. After that, it is added with the proper string.

Share
Posted in Concurrent Unit Testing | Leave a comment

Print This Post Print This Post  

Dumb Divide-and-Conquer Debugging

I’m running a few dumb divide-and-conquer tests to find out why the code is blocking (that’s generally how debugging this stuff works). Initially, I commented out everything in SyncPointRecorder.add(), and not surprisingly, everything worked. I wasn’t getting any data, of course, but the slave didn’t hang.

Now I commented out just the statement that adds the synchronization point to the list:

public static synchronized void add(ISyncPoint sp) {
if (_syncPoints==null) {
_syncPoints = new ArrayList();
}
// _syncPoints.add(sp);
}

Interestingly enough, now it hangs. I guess now I’ll venture into ArrayList to look for a reason.

Update

The constructor of ArrayList doesn’t seem to do anything but a new Object[10], so there isn’t a lot of interesting stuff to see. I wrote a quick hack to see if array allocation is the problem and replaced the ArrayList with a biiiig array (and assume that it never fills up, or I’d lose lots of data). The JPDA monitor reads out the array and resets the write index to 0.

public class SyncPointRecorder {
private static final int SIZE = 2 << 12; private static volatile ISyncPoint[] _syncPoints = new ISyncPoint[SIZE]; private static volatile int _index = 0; public static synchronized void add(ISyncPoint sp) { _syncPoints[_index] = sp; // hangs here _index = (_index + 1) & (SIZE-1); } }

However, that's not the issue either. Now the program hangs in line 6. What can go wrong in assigning a reference to an array entry? Huhumm...

Share
Posted in Concurrent Unit Testing | Leave a comment

Print This Post Print This Post  

Stuck in SyncPoint.add()

I’ve added some diagnostic tools to the JPDA monitor to analyze why and in what way the slave gets stuck. I’ve added counters that display successful updates, delayed updates, and the number of synchronization points in the slave list at the time of the last update attempt.

There are three scenarios:

  1. If everything is going well, then the successful updates counter keeps incrementing, and the synchronization point counter displays the number of points transferred during each update.
  2. If the JPDA monitor cannot update because the slave just always happens to be in SyncPoint.add(), but the program is actually advancing, then the delayed updates counter keeps incrementing, and the synchronization point counter keeps on incrementing as well, as the list does not get emptied.
  3. If the JPDA monitor cannot update because the slave is stuck in one and the same call to SyncPoint.add(), then the delayed updates counter keeps incrementing, but the counter for the synchronization points remains unchanged. That’s because more update attempts are made and get delayed, but no more synchronization points are added.

What I observe happening sometimes (very often, unfortunately), is the last behavior. That means that the slave program is actually stuck in the same call to SyncPointRecorder.add(). There’s no other way. If it moved out of that call but not into another call, it would exhibit the first behavior. If it moved out of the call and into another call, it would be the second.

I have no idea, though, why it gets stuck. Take a look at the source code in the previous posting. I don’t see any reason.

I’ve also noticed that every once in a while I still get a HotSpot VM error:

#
# An unexpected error has been detected by HotSpot Virtual Machine:
#
#  EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x6d72b030, pid=3980, tid=2848
#
# Java VM: Java HotSpot(TM) Client VM (1.5.0_04-b05 mixed mode)
# Problematic frame:
# V  [jvm.dll+0xeb030]

Again, no clue about that. And I have a NullPointerException in the deadlock detection after I do a manual update of the threads in the slave VM, but that’s probably just an oversight.

Share
Posted in Concurrent Unit Testing | Leave a comment

Print This Post Print This Post  

Working With Hiccups

During the night I meditated over the question of how to insert the header code for synchronized methods changed to synchronized blocks correctly. In the case I was considering, it was obvious that the instructions needed to be inserted before the instruction that was originally first, and that references to that instruction had to be relocated to still point to it. However, I wasn’t sure if that was always true, and I didn’t know if the exit code before ?return opcodes was correct.

I’m now pretty sure that in all cases, the header code needs to be inserted before the first opcode, and that references need to be relocated. Here’s my reasoning: Before, grabbing the lock was implicitly done by the JVM. Now, the method does it itself, but there’s no reason it should ever be done again. For the remainder of the method, it should still be as implicit as possible.

I also believe that the exit code should be inserted in the place of ?return opcodes, and references to it not be relocated. That’s what I was doing already. Again, my reasoning is that things need to still appear implicit to the rest of the method, and that means in this case the exit code needs to be executed whenever the method returns, so jumps should not go to the ?return instruction itself, but to the beginning of the exit code that precedes it.

I changed the instrumentor accordingly, and now the programs load and run. That’s good.

But when they’re running in the JPDA monitor, quite often they hang. I don’t know why. I keep getting the message “slave VM in edu.rice.cs.cunit.tm.syncPoints.SyncPointRecorder.add. postponing update”. I put that message there. I know when it’s supposed to occur. It just doesn’t make sense to me. I’ve also seen this behavior more often on the computer at work than at home.

Whenever the JPDA monitor is trying to make an update, i.e. read and clear the list the slave maintains, it checks if the slave is just in the process of adding to that list. If that’s the case, it postpones the update. If it went ahead and cleared the list, a race condition could cause the slave to throw a NullPointerException. However, the function is so short, I don’t know why it would be spending so much time in it. I also don’t know if it’s not returning or just calling it so often and at such a high frequency that it appears stuck in there.

Here’s the code for SyncPointRecorder:

/**
* Class that records synchronization points.
*
* @author Mathias Ricken
*/
@IncludeInRuntime
public class SyncPointRecorder {
/**
* List of synchronization points.
*/
private static volatile ArrayList _syncPoints =
new ArrayList();

/**
* Adds a synchronization point to the list.
* Note: This method has to be synchronized,
* but it may NOT be instrumented as such!
* An infinite recursion would be the result.
* The monitor application has to check that
* no thread is currently holding the lock on
* SyncPointerRecorder.class.
* Only then may it clear the list.
* @param sp synchronization point to add.
*/
public static synchronized void add(ISyncPoint sp) {
if (_syncPoints==null) {
_syncPoints = new ArrayList();
}
_syncPoints.add(sp);
}
}

This isn’t an optimal solution, but it should work. It might make sense to change this to a custom data structure, maybe a resizeable ring buffer, but I don’t think that’s what’s causing the program to hang.

I have the frightening feeling that completeness and robustness are inversely proportional, with a very disadvantageous proportionality constant…

Share
Posted in Concurrent Unit Testing | Leave a comment

Print This Post Print This Post  

Not Working :(

I just expanded the method to block instrumentation to the entire runtime, and unfortunately I’m getting an java.lang.IllegalMonitorStateException at sun.misc.URLClassPath.getLoader(Unknown Source). So something’s still wrong… :(

Fortunately, the source code in question has been released under the JRL, so now I’m doing a “Java source” vs. “uninstrumented” vs. “instrumented synchronized blocks” vs. “synchronized methods converted to blocks and instrumented synchronized blocks” comparison… that’ll be fun.

Update

By stepping through the bytecode of the fully instrumented getLoader method I’ve found at least one thing that’s wrong. Since the actual code is released under the JRL, I’ll show simplified code here. The method contains a while loop that begins at line 1, and a continue statement:

synchronized void getLoader() {
while(<1st condition>) {
...
if (<2nd condition>) continue;
...
}
...
}

In bytecode, it looks roughly like this:


if??? 12
...

if??? 8
// 2nd condition met!
goto 1 // goto top of while loop
// 2nd condition not met!
...
goto 1 // goto top of while loop

// code after while loop
...

This got instrumented and turned into bytecode similar to this:

aload\_0
invokestatic (SynchronizedMonitor.tryEnterBlock)
aload\_0
monitorenter
aload\_0
invokestatic (SynchronizedMonitor.enterBlock)

if??? 18
...

if??? 14
// 2nd condition met!
goto 1 // goto top of while loop
// 2nd condition not met!
...
goto 1 // goto top of while loop

// code after while loop
...
aload\_0
invokestatic (SynchronizedMonitor.leaveBlock)
aload\_0
monitorexit
return

// exception handler for all exceptions
aload\_0
invokestatic (SynchronizedMonitor.leaveBlock)
aload\_0
monitorexit
athrow // rethrow

The problem is the goto 1. When the code loops, the aload\_0; invokestatic; aload_0; monitorenter; aload\_0 invokestatic code is executed again. I don't know if that's what's causing the exception, but it's definitely wrong. It's quite clear that the goto must be to the line after this code. It's not clear to me yet if that's always the case, though.

Share
Posted in Concurrent Unit Testing | Leave a comment

Print This Post Print This Post  

A throw Is Not a Return

When I looked at the code to instrument synchronized blocks a few days ago, I noticed that athrow was not being treated as a “return instruction”, so I… fixed that. It seemed to be very similar to the ?return instructions: The method would exit, perhaps execute a finally handler, and that’s it. I shouldn’t have done that. While throwing an exception often is a rather quick way to exit a method, it’s not guaranteed that the method will be exited, whereas for ?return it is.

The result was that I introduced the “leave + unlock” block in front of each athrow opcode. If an exception was thrown, caught, and rethrown, the monitor would actually be unlocked several times, and the JVM doesn’t allow that. It throws an IllegalMonitorStateException, something that should happen when “a thread has attempted to wait on an object’s monitor or to notify other threads waiting on an object’s monitor without owning the specified monitor”, according to the Java API documentation. Unlocking an unlocked monitor isn’t mentioned there, but that probably makes sense: In Java, that can never happen. Using bytecode, it can.

So I… unfixed that. I also made several smaller bugfixes, added a few flags to some supporting tools, and ran some more tests. The stack issues are gone.

Share
Posted in Concurrent Unit Testing | Leave a comment

Print This Post Print This Post  

Stack Issue Seems Resolved

I put the code to query the thread stack frames back in to see if fixing the stack size helped, and it seems to work again. The interesting thing is that running the applications worked, as long as I didn’t ask for the stack frames, but as soon as I requested them, the VM died.

Here’s my theory: When the JVM is just running, it has a stack that always has the maximum size, or at least that one that isn’t really segmented into individual frames. The JVM just pushes and pops stuff on and off the stack. When my stack frame was too small, that didn’t matter. When the JVM runs an application, it ignores the stack frame size.

When it needs to return an array of stack frames, though, it needs to separate the one lump of stack into individual pieces. For this, it uses the information about the stack frame size contained in the code attributes. When this information isn’t right, it gets off track and the stack frames returned don’t actually correspond to the real frames.

I’ll have to test this a little more, but so far, it looks encouraging :)

Share
Posted in Concurrent Unit Testing | Leave a comment

Print This Post Print This Post  

Sometimes javac Does Optimize

Sometimes, javac apparently decides not to be utterly stupid. Sometimes it optimizes. Here’s the special case: When a program locks this, which is always present in local variable 0 in non-static methods, it does not allocate an additional local variable. I expected the following:

aload\_0 // load this
dup
astore\_1 // store this in local 1
monitorenter // lock this
...
aload\_1 // retrieve this from local 1
monitorexit // unlock this

But in this case, javac is smart enough to realize that aload_0 already contains this, so it generates

aload\_0 // load this
monitorenter // lock this
...
aload\_0 // load this
monitorexit // unlock this

But, of course, if the user declares a local variable, like in the following example, javac does not recognize this. This Java code

final Object temp = someField;
synchronized(temp) {
...
}

mercilessly generates this bytecode:

aload\_0// load this
getstatic 0004 // load field
astore\_1 // store in local 1
aload\_1 // restore from local 1
dup
astore\_2 // store in local 2
monitorenter // lock
...
aload\_2 // restore from local 2
monitorexit // unlock

Now I have to put more conditionals into my code. Yuck. I hope there aren’t more of these rare optimizations hidden somewhere. All of this gives me a bad feeling about relying on my perception of what javac generates. It would be much more prudent to just rely on the VM specifications, as I did before.

Share
Posted in Concurrent Unit Testing | Leave a comment

Print This Post Print This Post  

Invalid Assumptions Suck

I just found out I made invalid assumptions when I rewrote the synchronized block instrumentation code, and I hadn’t discovered my mistake until now, when I ran more general tests.

I assumed the structure of the monitorenter code always looked like this:

aload\_0 // load something
dup
astore\_1 // store in local
monitorenter // lock

I assumed that the instruction immediately before the dup would be sufficient by itself to put the object getting locked on the stack. However, that’s not the case, for example when a non-local variable is accessed:

aload\_0// load this
getstatic 0004 // load field
dup
astore\_1 // store in local
monitorenter // lock

Now, the two instructions before the dup are necessary. It gets worse: If the object put on the stack is the result of a function call, making that call twice may produce different results:

synchronized(someFunc()) {
...
}

or in bytecode:

aload\_0// load this
invokevirtual 0018 // call some method
dup
astore\_1 // store in local
monitorenter // lock

Even if I were to duplicate aload_0; invokevirtual 0018, the code would not do what I want. So apparently the real equivalent of what I want to do is this:

final Object temp = someFunc();
SynchronizedMonitor.tryEnterBlock(temp);
synchronized(temp) {
SynchronizedMonitor.enterBlock(temp);
try {
...
}
finally {
SynchronizedMonitor.leave(temp);
}
}

That boils down to bytecode like this (except more complicated because of javac’s ways):

aload\_0// load this
invokevirtual 0018 // call some method
astore\_1 // store return value in local temp
aload\_1 // restore from local temp
invokestatic (SynchronizedMonitor.tryEnter)
aload\_1 // restore from local temp
dup
astore\_2 // store in local 2
monitorenter // lock
aload\_1 // restore from local temp
invokestatic (SynchronizedMonitor.tryEnter)
...
aload\_2 // restore this from local 2
monitorexit // unlock
goto 26 // jump over finally handler

// handler for any exception (line 12)
astore\_3 // store exception in local 3
aload\_1 // restore from local temp
invokestatic (SynchronizedMonitor.leave)
aload\_2 // restore this from local 1
monitorexit // unlock
aload\_3 // restore exception from local 3
athrow // rethrow

...

So I have to introduce an additional local variable (which brings up the naming/equivalence issues again), store to it and reload from it several times. With several synchronized blocks in one method, it becomes more difficult to remember which local variable goes with which block. One thing that I probably can do is reuse the local variable already used by javac. In that case, local variables 1 and 2 would be replaced by a single local variable, or I could reorder the instructions and move the astore up, optimizing an unnecessary astore away. Both cases would not generate a one-to-one correspondence with javac, but it should be identical except for naming/equivalence again.

Now, if I weren’t trying to duplicate javac’s code, it would be as simple as this:

aload\_0// load this
invokevirtual 0018 // call some method
dup
astore\_2 // store in local 2
* dup
* dup
* invokestatic (SynchronizedMonitor.tryEnter)
monitorenter // lock
* invokestatic (SynchronizedMonitor.tryEnter)
...
aload\_2 // restore this from local 2
* dup
* invokestatic (SynchronizedMonitor.leave)
monitorexit // unlock
goto 26 // jump over finally handler

// handler for any exception (line 10)
astore\_3 // store exception in local 3
aload\_2 // restore this from local 1
* dup
* invokestatic (SynchronizedMonitor.leave)
monitorexit // unlock
aload\_3 // restore exception from local 3
athrow // rethrow

...

The beauty here is that the code is very tightly centered around monitorenter and monitorexit, and no new finally handler has to be introduced. The inserted instructions have been marked with a *.

Actually… now that I think of it, it’s likely that I don’t have to introduce a new code>finally handler anyway, because javac needs to make sure there is a hidden code>finally handler anyway to unlock and rethrow. But again, I wouldn’t get what javac generates, I wouldn’t get Java code that corresponds to it.

All of this is solvable, but I’m seriously beginning to doubt the value.

Share
Posted in Concurrent Unit Testing | Leave a comment

Print This Post Print This Post  

New Synchronized Block Instrumentor

I just finished changing the instrumentor for synchronized blocks. Now it generates bytecode that pretty much exactly matches hand-written Java code. This synchronized block

synchronized(this) {
foo();
}

with the bytecode

aload\_0 // load this
dup
astore\_1 // store in local 1
monitorenter // lock this
aload\_0 // load this
invokevirtual (foo) // call foo()
aload\_1 // restore this from local 1
monitorexit // unlock this
goto 18 // jump to return

// handler for any exception (lines 5-6)
astore\_2 // store exception in local 2
aload\_1 // restore this from local 1
monitorexit // unlock this
aload\_2 // restore exception from local 2
athrow // rethrow

return

gets turned into the bytecode

aload\_0 // load this
invokestatic (SynchronizedMonitor.tryEnter)
aload\_0 // load this
dup
astore\_1 // store in local 1
monitorenter // lock this
aload\_0 // load this
invokestatic (SynchronizedMonitor.enter)
aload\_0 // load this
invokevirtual (foo) // call foo()
aload\_0 // load this
invokestatic (SynchronizedMonitor.leave)
aload\_1 // restore this from local 1
monitorexit // unlock this
goto 26 // jump to return

// handler for any exception (lines 9-10)
astore\_2 // store exception in local 2
aload\_0 // load this
invokestatic (SynchronizedMonitor.leave)
aload\_1 // restore this from local 1
monitorexit // unlock this
aload\_2 // restore exception from local 2
athrow // rethrow

return

which is really close to this bytecode

aload\_0 // load this
invokestatic (SynchronizedMonitor.tryEnter)
aload\_0 // load this
dup
astore\_1 // store this in local 1
monitorenter // lock this
aload\_0 // load this
invokestatic (SynchronizedMonitor.enter)
aload\_0 // load this
invokevirtual (foo) // call foo()
aload\_0 // load this
invokestatic (SynchronizedMonitor.leave)
goto 22 // jump beyond athrow

// exception handler for all exceptions (lines 10-11, 17-18)
astore\_2 // store exception in local 2
aload\_0 // load this
invokestatic (SynchronizedMonitor.leave)
aload\_2 // restore exception from local 2
athrow // rethrow

aload\_1 // restore this from local 1
monitorexit // unlock this
goto 33 // jump to return

// exception handler for all exceptions (lines 8-24, 28-30)
astore\_3 // store exception in local 3
aload\_1 // restore this from local 1
monitorexit // unlick this
aload\_3 // restore exception from local 3
athrow // rethrow

return

which is what javac generates from this Java code:

SynchronizedMonitor.tryEnter(this);
synchronized(this) {
SynchronizedMonitor.enter(this);
try {
foo();
}
finally {
SynchronizedMonitor.leave(this);
}
}

Assuming the monitor methods whose calls have been inserted don’t throw exceptions, I think the instrumented version and the javac version are equivalent. But do I really have to make it this complicated? Is matching the javac output worth it?

I’ve also noticed that javac doesn’t seem to do any optimizations. I’m a bit shocked, but with a JIT compiler it probably makes sense. I actually hope this observation is correct and will remain valid. If javac does make optimizations, then this whole matching idea will immediately go out the door.

I’ll still have to make the synchronized methods to blocks instrumentor work again, and modify all the others… and of course I haven’t tested at all. More work to come, for sure. Good night.

Share
Posted in Concurrent Unit Testing | Leave a comment

Print This Post Print This Post  

Harder to Mimic

The last day was a little messed up. On Tuesday, I stayed at my office until 2:30 AM to install Visual Studio 2005 Beta 2 with all bells and whistles. All in all, it took about 12 hours. Since my bike is at the shop right now, I had to walk home, which took another 45 minutes. I was in bed around 5 AM. Today I slept in a little, then was sore as hell. I guess it’s rare that I walk 10 miles on a single day.

I’ve begun comparing the code Java generates and the code that I’m creating through instrumentation. I think it will be a bit harder than expected to exactly mirror what javac does. Here’s an example. This synchronized block

synchronized(this) {
try {
...
}
catch(RuntimeException e) {
...
}
}

gets translated into the following bytecode:

aload\_0 // this on stack
dup // this, this on stack
astore\_2 // store this in local 2
monitorenter // lock this
...
aload\_2 // retrieve this from local 2
monitorexit // unlock this
return

// exception handler for RuntimeException (line 6)
astore\_3 // store exception in local 3
...
aload\_2 // retrieve this from local 2
monitorexit // unlock this
goto 24 // jump to return

// exception handler to catch any other exception, unlock, and rethrow
// (lines 6-8)
astore 04 // store exception in local 4
aload\_2 // retrieve this from local 4
monitorexit // unlock this
aload 04 // retrieve exception from local 4
athrow // rethrow
return

The interesting thing here is that javac does not reload the reference for monitorexit from the source variable, but that it instead stores it in a local variable before the monitorenter and reloads the reference from there. Mimicking this behavior is harder than reloading: I have to extend the local variable pool correctly and insert more instructions. Mimicking javac’s product exactly might actually be nearly impossible. To establish equality between the code generated by javac and the instrumented code, the numbering of the local variables has to be identical, and I do not know the scheme javac uses. So this sort of is an alpha-equivalence issue. It should be possible to establish equivalence upto the numbering. But now I’m wondering… is this necessary?

While looking at the code and thinking about the local variable pool, I noticed that I need to check the stack size in all instrumentors. Whenever I’m putting values on the stack — and particularly whenever I use dup to duplicate something that’s already there — I have to increase the stack size. This might actually be related to the stack frame problems.

But now I’m logging out. It’s 5:30 AM, and I’m thoroughly out of my newly established normal sleeping pattern again X-(

Share
Posted in Concurrent Unit Testing, Uncategorized | Leave a comment

Print This Post Print This Post  

A Suggestion

Over the last few days I’ve created a launcher with a GUI to make starting the thread monitor easier. The command line was getting a little bit long: Every time, you had to append the boot classpath of the program to be monitored. The launcher also allows you to save configurations. That’s a big plus.

I guess I should also generalize the FileInstrumenter and add a GUI. Right now it bugs me a little that I still need to change the paths depending on whether I’m in my office or at home.

Today I found out again why Corky is my advisor and I’m his student, and not the other way around (not that I ever forget that). We were talking about my problems with the stack frames, and he suggested I do my instrumentations in a way that matches handwritten Java code. That way, it should be easier to verify.

Why didn’t that occur to me?

Share
Posted in Concurrent Unit Testing | Leave a comment

Print This Post Print This Post  

The Synchronized Native Problem

I haven’t done any serious tests with the synchronized method to block instrumentor, but even if everything checks out, there’s still a problem with synchronized native methods. Those have to be instrumented at the call site. I can’t think of a different way. Assume there is a method synchronized native void syncNative(). Then the call

...
syncNative();
...

will have to be changed into

...
synchronized(this) {
syncNative();
}
...

where syncNative is not actually synchronized anymore. Then the synchronized block will have to be instrumented. This is still a different strategy than the one I used before. We’ll see how this goes.

Fortunately, the number of synchronized native methods is relatively small:

class com.sun.java.util.jar.pack.NativeUnpack:
   initIDs
   start
   getNextFile
   getUnusedInput
   finish
   setOption
   getOption

class sun.awt.DebugHelperImpl:
   printlnImpl
   printImpl
   setCTracingOn

class sun.awt.image.codec.JPEGImageDecoderImpl:
   readJPEGStream
   writeJPEGStream

class sun.awt.windows.WDefaultFontCharset:
   canConvert

class sun.awt.windows.WMenuItemPeer:
   _dispose

class sun.awt.windows.WRobotPeer:
   _dispose()

class sun.awt.windows.WScrollPanePeer:
   setScrollPosition
   setSpans

class java.net.PlainDatagramSocketImpl:
   bind0
   peek
   peekData
   receive0

class java.text.Bidi:
   nativeBidiChars

class sun.font.FileFontStrike:
   getNullScalerContext

class sun.awt.windows.WWindowPeer:
   reshapeFrame

class sun.font.Type1Font:
   getGlyphCode

class sun.font.TrueTypeFont:
   getGlyphPoint

class sun.font.FileFont:
   getNullScaler
   getFontMetrics
   getGlyphAdvance
   getGlyphMetrics
   getGlyphImage
   getGlyphOutlineBounds
   getGlyphOutline
   getGlyphVectorOutline

class sun.font.FontManager:
   getFontPath
   setNativeFontPath

class sun.awt.windows.WComponentPeer:
   pShow
   hide
   enable
   disable
   updateWindow
   reshape
   dispose
   setFont
   start

class java.io.WinNTFileSystem:
   deleteOnExit

class java.io.Win32FileSystem:
   deleteOnExit

class java.lang.Throwable:
   fillInStackTrace

Ugh. Relatively.

Share
Posted in Concurrent Unit Testing | Leave a comment

Print This Post Print This Post  

Stoopid

Sometimes I seem to lose track of the big picture. The instrumentor I’m writing right now converts (non-native) synchronized methods to unsynchronized methods and synchronized blocks, which subsequently get instrumented just like any other synchronized block.

I was just wondering why so much rewriting was going on — it turned out I was inserting the “try enter”, “enter”, and “leave” notifications in both instrumentors. They don’t belong in the one that merely converts. D’uh.

Share
Posted in Concurrent Unit Testing | Leave a comment

Print This Post Print This Post  

Brunch Break

I’m going to take a break for some Saturday brunch now. I haven’t actually run the generated bytecode yet, but it looks good. I’m impressed with the code I wrote last summer.

One thing that I’ll definitely have to investigate is how this code and the Java VM will react if there already was a catch-all handler, and I add another one. My intuition right now is that my code would add a second catch-all handler that is unnecessary. The question is whether the JVM will barf. I guess I can filter it out.

Share
Posted in Concurrent Unit Testing | Leave a comment

Print This Post Print This Post  

Working

I rolled back to IDEA 3273, and this actually seems stable. I’m impressed by JetBrain’s customer support, though. It turns out I actually had been able to create bug reports — about four or five of them. They are investigating the issue, but told me to disable native Perforce support. I haven’t tried it yet, I want to get the issue I’m working on right now out of the way, but I will tinker around with it later.

Right now I’m writing an instrumentation strategy that takes a synchronized (non-native) method and converts it to a non-synchronized method with a synchronized block in it that locks this or this.getClass(). Right now, it converts the function

public synchronized void test(ThisTest t) {
try {
System.out.println(t);
return;
}
catch(RuntimeException e) {
e.printStackTrace();
}
}

and its bytecode

[ 0] getstatic 0006
[ 3] aload\_1
[ 4] invokevirtual 0007
[ 7] return
[ 8] astore\_2
[ 9] aload\_2
[10] invokevirtual 0009
[13] return
[14] --

Exception from PC 0 to 7, handler at PC 8, catch RuntimeException

to this bytecode:

[ 0] * aload\_0 // this
[ 1] * monitorenter
[ 2] getstatic 0006
[ 5] aload\_1
[ 6] invokevirtual 0007
[ 9] * aload\_0
[10] * monitorexit
[11] return
[12] astore\_2
[13] aload\_2
[14] invokevirtual 0009
[17] * aload\_0
[18] * monitorexit
[19] return
[20] * aload\_0
[21] * monitorexit
[22] * athrow
[23]

Exception from PC 0 to 9, handler at PC 12, catch RuntimeException
Exception from PC 0 to 19, handler at PC 20, catch all

Inserted bytecode has been marked with a * in front. The last five lines are part of an exception handler for anything Throwable to make sure the lock gets released even if an exception ripples up the stack.

I’ll still have to make sure the exception table is right. That brought up another question, though: Should athrow be considered a “return instruction”? It probably should be… it’s a place where control flow can exit a function.

Update

Fixed errors. See more recent post.

Share
Posted in Concurrent Unit Testing, Uncategorized | Leave a comment

Print This Post Print This Post  

IDEA Problems

I’ve been having a lot of problems with my favorite IDE lately. Somehow, IntelliJ IDEA keeps crashing, without any message box and without any discernable pattern. All I get is one of those hs\_log\_pid*.log files that I learned to love so much during my own adventures in the JVM.

I still don’t know what’s going on. I’m getting an EXCEPTION\_ACCESS\_VIOLATION in native code in JNIWrap.dll. No clue what that is. I’m running Java 1.5.0_03-b07, and experienced this with both IDEA builds 3386 and 3397. It’s a pretty big mess, since I changed both my machine, the Java VM, and the IDEA build at the same time. I rolled back to IDEA 3273, and… I’m almost scared to write it… it seems to be stable.

The most ironic part is that I can’t even submit a bug report. JetBrain’s defect tracking website returns a “NullPointerException”… ;)

Elspeth Simpson, a recent Rice Computer Science graduate and one of the major contributors to DrJava, found a picture of us at this year’s SIGCSE conference. I like the picture so much, I have to publish it here. Thanks, Elspeth!

SIGCSE 2005: Elspeth, Dan, Corky and I

SIGCSE 2005: Elspeth, Dan, Corky and I

Share
Posted in Pictures, Uncategorized | Leave a comment

Print This Post Print This Post  

Installation Marathon

I spent Saturday and Sunday installing program over program. It’s hard to imagine how much stuff I had on my computer. I used a list of programs that I had made the summer before when I reinstalled Windows, added a few programs that I had begun to use (miktex, for example), and removed others. I actually didn’t install quite a few programs… still I’m not quite done.

Exporting all the settings is quite a pain too, especially since some of the programs don’t run on my old machine anymore. The 120 GB hard drive is missing, and all the drive letters have changed. I think I’m quite close to having this computer in a working condition. IDEA and Perforce are installed, as is VS 2005 Beta 2. I haven’t installed VS 2003 Enterprise yet… I’m not sure if I need to.

Getting the virus scanner installed was more difficult than it should be — again. Last year, VirusScan 7.1.0 would not work properly on Windows 2003 Server, so I got version 7.0.0. That still works, but now it doesn’t update anymore, so my virus definition files are from 2003. Rice offers VirusScan 8 to the entire community, but somehow my login wouldn’t work. IT uses the same login information for downloads as for IMAP mail, and I could log into the latter, so I know my password was right. In the end, I managed to get VirusScan 8 elsewhere. It was still ridiculous.

I then celebrated July 4th with a bunch of friend from Rice. Nice weather, barbecue, beer, and fireworks. I had a fantastic time.

Share
Posted in Uncategorized | Leave a comment

Print This Post Print This Post