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

Provide high level API for inserting code in constructor before super/this call #878

Open
kriegaex opened this issue Jun 5, 2020 · 2 comments
Assignees

Comments

@kriegaex
Copy link

kriegaex commented Jun 5, 2020

This is loosely related to #857 because it could help improve the semantics of constructor enter/exit advices, too, making them functionally equal to method advices by permitting the user to conditionally decide during runtime whether to "skip" constructor execution (not really, but skip original code execution in a chain of super constructors). I have implemented this scheme in Javassist already, so I know that it works, see also my sample code in #870. @raphw told me in Gitter to create this issue because obviously what I want is already possible in ByteBuddy (BB) in two ways:

  1. Use ASM API: straightforward for JVM byte code experts maybe, but not for normal BB users who use BB precisely because they do not have ASM abilities and need a high level API.

  2. Enter the desired code in an on-enter advice, call a pseudo method where the actual super/this call should later be and then replace that method call by the super/this call. Ralph did not tell me exactly how he thinks this is to be done, but I guess he means that there should be a second transformation modifying the result of the first one. So for now I am also stuck here (or I would be if I did not have my Javassist solution). He said he can build a high level API around this scheme.

Background: The JVM permits to insert any byte code before the eventual super/this call (as long as it does not access this or instance fields, in simplified terms), even though in Java source code that is not permitted because super/this calls have to be the first instructions in any constructor. The byte code verifier also checks this when loading classes or retransforming them via instrumentation. So if you want to skip constructor execution, you have to insert something like: if (myCondition) { doThings(); super(0, null, false); } I.e. you also have to call super/this when skipping the original super/this call, but you can call it with other parameters, thus avoiding any side effects by using only default values. If done for the whole constructor chain up to the super class extending Object, this helps avoid object initialisation, which is very helpful when creating mocks. This works nicely even for bootstrap classes, even final ones which have already been loaded. I just want to be able to more easily do it with BB in order to avoid the dependency on another byte code engineering framework (at the moment I also use Javassist).


Related to this feature, the following would be helpful (maybe it already exists somewhere in the big BB treasure trove of features, but I have not bumped into it yet):

  • convenience method to determine the default value for any given type, also primitive ones, i.e. null, 0, '\0', false, (short) 0, 0L, 0.0f, 0.0d
  • convenience method to call super/this with all parameters set to above default values
  • convenience method returning an ordered collection (list, stack, array) of super classes for a given class
@raphw raphw self-assigned this Jun 7, 2020
@raphw
Copy link
Owner

raphw commented Jun 7, 2020

This would require some gymastics to reflect the target constructor. I see a possibility by having an extra annotations that could be used on a method to represent this call and to translate it accordingly. Stack map frame translations will however be tricky.

Certainly something to explore, I will look into it eventually!

@kriegaex
Copy link
Author

kriegaex commented Jul 2, 2020

As I just said when closing #870, I have migrated to the low level API of ASM, but looking back at the journey and all the detail work I still very much like the idea of having some more high level API support for this kind of thing. Other than copying & pasting from ASMifier output, how to routinely and efficiently use ASM still eludes me.

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

No branches or pull requests

2 participants