API suggestions
Dan Heidinga
heidinga at redhat.com
Wed Mar 22 12:42:07 UTC 2023
On Wed, Mar 22, 2023 at 8:19 AM Brian Goetz <brian.goetz at oracle.com> wrote:
> Before we get into what API changes are needed, let's sync on the problem
> first.
>
> 1. CodeTransform has an `atStart` method just as it has an `atEnd`
> method, and I presume overriding `atStart(builder)` is adequate to your
> need. Is the issue simply that there is no canned combinator for
> startHandler as there is for endHandler?
>
> 2. Adding an annotation is complicated, and we explored a number of
> solutions before settling in the current place. There are three cases:
>
> - There is no RVAA, so you have to add one
> - There is an RVAA, but it already has your annotation, so there's
> nothing to do
> - There is an RVAA, and it doesn't have your annotation, so you have to
> transform it
>
> (Actually there is a fourth case: it has your annotation, but with
> _different properties_; there is @Foo(3) but you want to add @Foo(4). Now
> what do you do? Replace it? Leave it? Add both?)
>
> The trickiness is compounded by the fact that the latter two cases can be
> handled by transforming the element for RVAA, but the first case can't be
> handled until the end handler, and you have to remember whether you saw an
> RVAA or not. So the process is inherently stateful. Some options were
> covered in this thread (which talked about NestMembers, but the story is
> the same for annotations.)
>
>
> https://mail.openjdk.org/pipermail/classfile-api-dev/2022-August/000108.html
>
> Here's the recommended code for that situation:
>
> () -> new ClassTransform() {
> boolean foundNM = false;
>
> void accept(ClassBuilder b, ClassElement e) {
> switch (e) {
> case NestMembersAttribute a -> { transform a; foundNM =
> true; }
> ... other transform stuff ...
> }
> }
>
> void atEnd(ClassBuilder b) {
> if (!foundNM)
> builder.accept(NestMembersAttribute.of(...));
> }
> }
>
> It's irritating because you have to do three things -- keep track of some
> state, rewrite an attribute if you see it, and generate an attribute if you
> don't, but it's really not so lengthy or hard to follow.
>
Here's a link to my various attempts to find a better way to express this
[0] when exploring NestMember attribute changes. Wrapping Brian's
suggested pattern in a named class makes it a little easier to read at the
point of use but there's no single pattern for this (that I've found) that
results in significantly cleaner code.
TLDR: Brian's proposed code is the best you can do for this.
--Dan
[0]
https://github.com/DanHeidinga/jdk-sandbox/blob/9c5bf15522e76ebc106a433758c87623dec4827b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/GenerateLambdaClassesPlugin.java#L238-L385
>
> I can imagine capturing this in a combinator, where you provide two
> lambdas, one a transform on your favorite attribute, and one a supplier of
> that attribute, but I don't think it will be that much easier to use, it
> just automate managing and acting on the boolean.
>
>
>
>
> On 3/21/2023 11:38 PM, - wrote:
>
> Hi,
> After housekeeping the few tests after the latest integration of
> additional constants in ConstantDescs, I have found two potentially
> common patterns in bytecode manipulation and wish to suggest new APIs:
>
> 1. Injection of code in the beginning of methods
> Currently, our CodeTransform only has an endHandler; however, this is
> less useful, for a method can have multiple exit points. Usually to
> track method calls, bytecode manipulation, such as those in jfr and
> instrumentation, inject at the beginning of methods, which is
> guaranteed to be on the code path.
>
> Thus, I suggest a `startHandler(Consumer<CodeBuilder>)` for
> CodeTransform for this purpose, instead of having to explicitly
> override atStart(CodeBuilder) in non-lambda CodeTransform.
>
> 2. Adding new annotations
> In ASM, annotation injection is done simply via extra annotation
> visitor calls, which makes it compatible for either single or multiple
> annotations. In contrast, in the Classfile API, if we want to add an
> annotation, feeding a new RuntimeVisibleAnnotationAttribute will
> destroy the previous RuntimeVisibleAnnotationAttribute, and handling
> via a stateful ClassTransform is a bit too lengthy for users.
>
> I don't know if we should have an API like Map::computeIfAbsent for
> attributes or if we will simplify it via other means.
>
> Chen Liang
>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/classfile-api-dev/attachments/20230322/4284046b/attachment-0001.htm>
More information about the classfile-api-dev
mailing list