Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

use Instrumentation#retransformClasses to hotswap #566

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

hengyunabc
Copy link
Contributor

@skybber
Copy link
Contributor

skybber commented Aug 16, 2024

I have very similar idea, btw, where is the classToByteCodeMap cleared?

@skybber
Copy link
Contributor

skybber commented Aug 16, 2024

The second problem I see is atomicity. Each redefinition batch should be isolated from the others. In your solution, two consecutive hotswap() calls, R1 and R2, could redefine the same class, R1.C and R2.C, and only the last change (R2.C) would be processed by the redefinition. This could lead to a linkage error in DCEVM.

@hengyunabc
Copy link
Contributor Author

  1. The classToByteCodeMap does not need to be cleared. It represents the final version of the updated bytecode.
  2. There indeed might be atomicity issues. However, since reTransform is asynchronous, try to resolve it would require implementing some complex counting mechanisms. Personally, I believe this would introduce unnecessary complexity. Moreover, if a mismatch in counts occurs, should we stop everything or continue proceed?

@hengyunabc
Copy link
Contributor Author

If it is truly necessary to address atomicity issues, the following solution can be considered:

  • Add some data in the bytecode to record which batch it belongs to. For example, add a meaningless annotation to the class, such as @Hotswap(byteCodeVersion = 111). In the Transformer, collect the information from the annotation, and then it will be possible to know the final bytecode version of each class.

@skybber
Copy link
Contributor

skybber commented Aug 16, 2024

May be there could a que of byte code be for each class in the weak map and the retransform method would pop bytecode from the que.

@hengyunabc
Copy link
Contributor Author

May be there could a que of byte code be for each class in the weak map and the retransform method would pop bytecode from the que.

However, in extreme cases, confusion may still occur. For example, if another Java agent modifies the bytecode of the same class, triggering a redefine or reTransform, it becomes impossible to distinguish where the Transformer's callback was triggered from.

@skybber
Copy link
Contributor

skybber commented Aug 16, 2024

May be there could a que of byte code be for each class in the weak map and the retransform method would pop bytecode from the que.

However, in extreme cases, confusion may still occur. For example, if another Java agent modifies the bytecode of the same class, triggering a redefine or reTransform, it becomes impossible to distinguish where the Transformer's callback was triggered from.

I think that using queue+pop is better than overriding and retaining unnecessary bytecode in the map. When autoHotswap=true is enabled, there could be numerous redefinitions. Minecraft developers have reported that they can fill 500MB to 1GB of code cache with redefined classes.

@hengyunabc
Copy link
Contributor Author

I think that using queue+pop is better than overriding and retaining unnecessary bytecode in the map. When autoHotswap=true is enabled, there could be numerous redefinitions. Minecraft developers have reported that they can fill 500MB to 1GB of code cache with redefined classes.

Retaining the final byte[] is necessary. Otherwise, if other Java agents trigger a redefine/retransform, it will cause the hotswap to no longer be effective.

One possible approach is to implement a disk-based cache, writing the byte[] to disk.

@skybber
Copy link
Contributor

skybber commented Aug 16, 2024

Interesting. I'll take some time to look into this. In the meantime, could you share more about your use case? I'm really curious.

@hengyunabc
Copy link
Contributor Author

Interesting. I'll take some time to look into this. In the meantime, could you share more about your use case? I'm really curious.

We are currently facing an issue when using the hotswap agent:

Users are unsure whether a modified class has been successfully hot-updated. Although there may be some log outputs, users still do not know if the changes have taken effect.

We are considering allowing users to retrieve the runtime bytecode to determine if it has taken effect, for example, using: https://arthas.aliyun.com/en/doc/jad.html.

Therefore, we strongly prefer to use retransformClasses to update bytecode rather than redefineClasses.

@skybber
Copy link
Contributor

skybber commented Aug 19, 2024

If logging of redefinition is only reason for it then I recommend to use -Xlog:redefine+class*=info. It turns on basic redefinition info. If you have another use case for it, then we could add optional retranformation to HA, may be it can be enabled by a new HA option (retransform=true, both in hotswap-agent.properties and HA options), then we can use the patch as you proposed (with the option).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants