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:


GeSHi Error: GeSHi could not find the language jvm (using path /homepages/42/d86928234/htdocs/blog/wp-content/plugins/codecolorer/lib/geshi/) (code 2)

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:


GeSHi Error: GeSHi could not find the language jvm (using path /homepages/42/d86928234/htdocs/blog/wp-content/plugins/codecolorer/lib/geshi/) (code 2)

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:

1
2
3
synchronized(someFunc()) {
    ...
}

or in bytecode:


GeSHi Error: GeSHi could not find the language jvm (using path /homepages/42/d86928234/htdocs/blog/wp-content/plugins/codecolorer/lib/geshi/) (code 2)

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:

1
2
3
4
5
6
7
8
9
10
11
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):


GeSHi Error: GeSHi could not find the language jvm (using path /homepages/42/d86928234/htdocs/blog/wp-content/plugins/codecolorer/lib/geshi/) (code 2)

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:


GeSHi Error: GeSHi could not find the language jvm (using path /homepages/42/d86928234/htdocs/blog/wp-content/plugins/codecolorer/lib/geshi/) (code 2)

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

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