Wrong Insertion Method

I finally found the problem why the boolean $$$oldThread$$$ flag wasn’t sticking: I seemed to set it to false, but the next time I looked at it, it was true again.

The Java code basically is this:

public static synchronized void compactWait(long code, long tid) {
if (!_replaying) {
return;
}

monitorEnter(_waitAlgoObj);

if (isOldThread()) {
// If this is NOT the first sync point for this thread...
...
}
else {
// Otherwise, if it was the first time... set flag.
setOldThread();
...
}

// More code...
...

monitorEnter(), isOldThread() and setOldThread() are dummy marker methods and get replaced with bytecode during instrumentation:

  • monitorEnter() becomes just a monitorenter
  • isOldThread() becomes invokestatic java/lang/Thread.currentThread()Ljava/lang/Thread;
    getfield java/lang/Thread.$$$oldThread$$$Z
  • setOldThread() becomes invokestatic java/lang/Thread.currentThread()Ljava/lang/Thread;
    iconst_1;
    putfield java/lang/Thread.$$$oldThread$$$Z

The Java code above roughly corresponds to this bytecode:

getstatic edu/rice/cs/cunit/SyncPointBuffer._replayingZ
ifne 4
return
getstatic edu/rice/cs/cunit/SyncPointBuffer._waitAlgoObjLjava/lang/Object;
invokestatic edu/rice/cs/cunit/SyncPointBuffer.monitorEnter(Ljava/lang/Object;)V
invokestatic edu/rice/cs/cunit/SyncPointBuffer.isOldThread()Z
ifeq 13

// If this is NOT the first sync point for this thread...
...
goto 17

// Otherwise, if it was the first time... set flag.
invokestatic edu/rice/cs/cunit/SyncPointBuffer.setOldThread()V
...

// More code...
...

My faulty instrumentation of the marker methods, however, generated this bytecode:

getstatic edu/rice/cs/cunit/SyncPointBuffer._replayingZ
ifne 4
return
getstatic edu/rice/cs/cunit/SyncPointBuffer._waitAlgoObjLjava/lang/Object;
monitorEnter
invokestatic java/lang/Thread.currentThread()Ljava/lang/Thread;
getfield java/lang/Thread.$$$oldThread$$$Z
ifeq 18

// If this is NOT the first sync point for this thread...
...
goto 20

// Otherwise, if it was the first time... set flag.
invokestatic java/lang/Thread.currentThread()Ljava/lang/Thread;
iconst_1;
putfield java/lang/Thread.$$$oldThread$$$Z
...

// More code...
...

I was inserting the correct bytecode, but I was modifying call targets it in a way such that calls to the insertion location would go to the opcode just PAST the inserted code, whereas it should have gone right TO the inserted code. Now I can move on and face new, exciting problems ;-)

Share

About Mathias

Software development engineer. Principal developer of DrJava. Recent Ph.D. graduate from the Department of Computer Science at Rice University.
This entry was posted in Concurrent Unit Testing. Bookmark the permalink.

Leave a Reply