Skip to main content

JVMTI RedefineClasses and classes derived from Thread

9 replies [Last post]
vss
Offline
Joined: 2007-12-06

Hi,

I'm using RedefineClasses() to change classes derived from java.lang.Thread. It seems that a new class is successfully loaded (as -Xtrace:0x04000000 shows), but running threads still use the original class, not the new one. Is my observation correct? Is there such a limitation/feature in the implementation of RedefineClasses?

I use one of the latest subversion snapshots.

Thanks.

Reply viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
billp
Offline
Joined: 2006-09-19

I was able to reproduce this so I'll work on a fix.

bill

bharatgusain
Offline
Joined: 2009-02-05

Hi,
I have a somewhat similar problem and identical scenario, i understand that redefining a class that is extended from a thread will not lead to executing new byte code due to old stack frame, but i encountered a weird problem and would like to describe this below:
I am using JVMTI's redefine class features and instrumenting the bytecode during runtime.
my first scenario:
1) I run a sample application (consider class A) that prints a simple message in its method, this method is called infinitly from another threaded class (consider class T) which has a run method.
2) After the sample application (class A) gets loaded by CVM i immediately change its bytecode using JVMTI_EVENT_CLASS_FILE_LOAD_HOOK, replaces its bytecode to print some extra messages(). I redefines it and loaded the instrumented class.

3) After Reloading the sample class (class A) with instrumented class i got the desired instrumented output.

This is the way i wanted it to always behave, but consider another scenario:

1) I run a sample application (consider class A) that prints a simple message inside a method, this method is called infinitly from another threaded class (consider class T) inside it's run method(i am running a thread that calls class A's method infinitly).

2) After the application (class A) executed, i wait for some time doing nothing and let the application run for quite some time (8-10 minutes).

3) Now change intercept the JVMTI_EVENT_CLASS_FILE_LOAD_HOOK event and replace it's bytecode (same as i have done in scenario 1), redefines the sample loaded class & reloads it.

4) After Reloading the sample class (class A) with instrumented class what i saw that it still executes the older class only, this is not what i expected it to do.

the only difference in these 2 scenario is the idle wait time during which the class A's method is called infinitly from thread.
so immediate instrumentation works well but instrumentation after some time don't work.

I Checked the stack also but could not found any clue, also this behaviour is guaranteed if you wait for 10 minutes.

Any help in this regard would be appreciated.

Regards
bharat..

billp
Offline
Joined: 2006-09-19

This is a limitation in the pMEa JVMTI implementation. The primary use of RedefineClasses is to support Netbeans profiling as well as edit-and-continue debugging with Netbeans. In either case, any existing stack frames that have the old methods referenced will continue to use the old method code. The Netbeans profiler redefines classes as the classes are loaded into the VM before any methods are executed so it doesn't hit this particular limitation.

bill

vss
Offline
Joined: 2007-12-06

Does this limitation apply only to classes derived from Thread/Runnable or any class that has methods on the stack?

Say, A.method1() is on the stack, and it's a long running method. While A.method1() is running, I redefine class A, so that A.method2() has a new code. Will the new A.method2() take effect while the old A.method1() is still running? Or the entire class is locked while it has any methods on the stack?

Thanks.

billp
Offline
Joined: 2006-09-19

Only individual methods will be effected, not the whole class. So in your example the old method1() will continue to run but the new method2() will take effect at its next invocation.

bill

vss
Offline
Joined: 2007-12-06

Thanks for the response, and I would appreciate if you could clarify one point.

>Only individual methods will be effected, not the whole class

except when the class derives from Thread/Runnable in which case the whole class is locked until the thread exits. Is that right?

billp
Offline
Joined: 2006-09-19

Could you define what you mean by "the whole class is locked"? I don't doubt that a class subclassing Thread/Runnable might have some special issues but from looking at the code I don't see anything that jumps out at me. I'll have to try a few examples to see if there is something amiss.

bill

vss
Offline
Joined: 2007-12-06

I'll try to describe our scenario.

Our class HelloTest extends Thread and runs for a long time. While it's running, our JVMTI agent calls RedefineClass to reload HelloTest. The agent intercepts JVMTI_EVENT_CLASS_FILE_LOAD_HOOK and replaces the bytecode. The new bytecode contains minor changes for myreport() method (instead of "i" it prints i*10).

Here is the log. Instead of "Thread reports: 19" I expect to see "Thread reports NEW: 190", but he old report continues running until the thread exits (iteration 30) and a new instance starts. Then it prints "Thread reports NEW : 10".

----
Thread reports: 17
Thread reports: 18
AGENT: 22240: Redefine bytecode length: 1212
JVMTI: suspend thread: 0x87a5dc0
JVMTI: suspend thread: 0x8775ca8
JVMTI: suspend thread: 0x876b9d0
JVMTI: suspend thread: 0x85d99f8
AGENT: 22240: JVMTI_EVENT_CLASS_FILE_LOAD_HOOK HelloTest 0x87598d0 len=1212 jni=0x8792044
AGENT: 22240: ... bytecode changed, new len 1246
AGENT: 22240: JVMTI_EVENT_CLASS_FILE_LOAD_HOOK changed HelloTest len=1246
JVMTI: Redefine: newroot 0x875816c, 0xb787c854
JVMTI: Redefine: HelloTest, oldcb: 0x877b498, newcb 0x87bb750, klass 0x8792e90, 0xb787c854, oldCP 0x877b4f0, newCP 0x87bb7a8
JVMTI:old: , oldMB 0x877b644, mlocs 2, mcap 13
JVMTI:new: , newMB 0x87bb8cc, mlocs 2, mcap 13
JVMTI:old: , oldMB 0x877b660, mlocs 2, mcap 13
JVMTI:new: run, newMB 0x87bb8e8, mlocs 3, mcap 14
JVMTI:old: run, oldMB 0x877b67c, mlocs 3, mcap 14
JVMTI:new: myreport, newMB 0x87bb904, mlocs 2, mcap 15
JVMTI:old: myreport, oldMB 0x877b698, mlocs 2, mcap 15
JVMTI:new: setStopFlag, newMB 0x87bb920, mlocs 2, mcap 13
JVMTI:old: setStopFlag, oldMB 0x877b6b4, mlocs 2, mcap 13
JVMTI:new: , newMB 0x87bb93c, mlocs 2, mcap 13
JVMTI: resume thread: 0x87a5dc0
JVMTI: resume thread: 0x8775ca8
JVMTI: resume thread: 0x876b9d0
JVMTI: resume thread: 0x85d99f8
AGENT: 22240: Redefine OK: 0.01 sec
Thread reports: 19
Thread reports: 20
...
Thread reports: 30
Thread reports: 31
JVMTI: Post thread end: ee 0x8790818
AGENT: 22774: JVMTI_EVENT_THREAD_END: 0x87a9cf0
Thread reports NEW : 10
Thread reports NEW : 20
----

Here is the class:

public class HelloTest extends Thread {

boolean stop = false;

public void run() {

int i = 0;
while( !stop ) {
i++;
myreport(i);
try {
sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}

if( i > 30 ) return;
}
}

private void myreport(int i) {
System.out.println( "Thread reports: " + i);
}

public void setStopFlag(boolean flag) {
this.stop = flag;
}
}

billp
Offline
Joined: 2006-09-19

Question, is this a JIT enabled build (CVM_JIT=true)? If so, then the myreport() method may be compiled in which case you would get the result you are seeing. Run with -Xjit:compile=none and see if it behaves differently. If there is no JIT then I'll have to try to duplicate the problem and see what's up.

bill