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 amonitorenter
isOldThread()
becomesinvokestatic java/lang/Thread.currentThread()Ljava/lang/Thread;
getfield java/lang/Thread.$$$oldThread$$$ZsetOldThread()
becomesinvokestatic 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 ;-)