1

We currently use premain to transform all classes before they have been loaded. But we want to make the transformation under control, Which means we can remove/re-add the code we inserted at the methods.

So we found the retransform, but i am not quite understand it.

  1. can we retransform classes loaded?
  2. if it can be done, will the instances of retransformed classes run the retransformed code?
  3. if it can't be done, is there any technology to change the code of some specified method at runtime.

UPDATED

For example, we have class A. Class A has two method foo() and bar():

void foo() {
    while(true) {
        bar();
    }
}
void bar() {
    System.out.println("a");
}

we call Instrument.retransformClasses(A.class). and change bar() to:

void bar() {
    System.out.println("b");
}

If there is a thread already invoking foo(), can we have the output:

...
a
a
a
b
b
b
...

if not, is there any way to implement it?

Meilun Sheng
  • 129
  • 1
  • 1
  • 7
  • What do you mean by "transform"? – byxor Aug 25 '16 at 08:22
  • 1
    Possible duplicate of [Update Java code during runtime](http://stackoverflow.com/questions/3079280/update-java-code-during-runtime) – CloudPotato Aug 25 '16 at 08:23
  • we currently implement a ClassFileTransformer to insert some code on every method of classes which have a special annotation on it. As my understanding, transform is changing bytecodes of class(at least, it looks like changing bytecodes, according to javadoc of ClassFileTransformer#transform()). – Meilun Sheng Aug 25 '16 at 08:28
  • Have you tried `Instrumentation.retransformClasses()`? https://docs.oracle.com/javase/7/docs/api/java/lang/instrument/Instrumentation.html#retransformClasses(java.lang.Class...) – Little Santi Aug 25 '16 at 08:54
  • @Blobonat so it means we can add transformers in agentmain and call Instrumentation.redefineClasses() to do the job? But how can we get the ClassDefinition? call redefineClasses() in ClassFileTransformers? – Meilun Sheng Aug 25 '16 at 08:55
  • @LittleSanti that is what i can't understand. if the class A is loaded, and there is a stack like : A.c(), A.b(), A.a(). The A.c() will call A.d(), and d() is retransformed before d() is invoked. Will the new version of d() be executed? or the old version does? – Meilun Sheng Aug 25 '16 at 09:05
  • Look at the docs: "If a retransformed method has active stack frames, those active frames continue to run the bytecodes of the original method. The retransformed method will be used on new invokes.". Does that answer your question? – Little Santi Aug 25 '16 at 09:09
  • i updated the question. i'm not quite understanding it. You see, transformer change the bytecode of the class, not the method. How can it know which method is retransformed? – Meilun Sheng Aug 25 '16 at 09:16

1 Answers1

1

So you already have a ClassFileTransformer to transform a class' bytecode before it is loaded and installed in the JVM. And now you would want to re-transform again along the JVM lifecycle, isn't it?

Well, retransformation can be done through Instrumentation, through the Instrumentation.retransformClasses method. But first, you have to ensure that retransformation is supported by calling Instrumentation.isRetransformClassesSupported.

When will this retransformation have effect? According to the javadocs:

If a retransformed method has active stack frames, those active frames continue to run the bytecodes of the original method. The retransformed method will be used on new invokes.

That means that, in your example, foo() invokes bar() repeatedly. If meanwhile bar is retransformed, the transformed code will have effect the very next iteration which calls bar.

I will add some more complexity to your example:

void foo() {
    while(true) {
        bar();
    }
}

void bar() {
    myRetransform();
    System.out.println("a");
}

void myRetransform() {
    // This is where a retransformation of class A, method bar, is triggered.
}

When the retransformation is triggered, the current stack frame is:

  • myRetransform
  • bar
  • foo

There is an active call stack frame with bar into it, so when myRetransform returns it will still print an "a" in the system.out.

Then, bar will return and leave the current stack frame like this:

  • foo

And now is when the last triggered transformation will take effect. I.e: in the very next invocation to bar.

Little Santi
  • 8,563
  • 2
  • 18
  • 46