<html><head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  </head>
  <body>
    <font size="4"><font face="monospace">Before we get into what API
        changes are needed, let's sync on the problem first.  <br>
        <br>
        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? 
        <br>
        <br>
        2.  Adding an annotation is complicated, and we explored a
        number of solutions before settling in the current place.  There
        are three cases:<br>
        <br>
         - There is no RVAA, so you have to add one<br>
         - There is an RVAA, but it already has your annotation, so
        there's nothing to do <br>
         - There is an RVAA, and it doesn't have your annotation, so you
        have to transform it<br>
        <br>
        (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?)<br>
        <br>
        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.)<br>
        <br>
           
<a class="moz-txt-link-freetext" href="https://mail.openjdk.org/pipermail/classfile-api-dev/2022-August/000108.html">https://mail.openjdk.org/pipermail/classfile-api-dev/2022-August/000108.html</a><br>
        <br>
        Here's the recommended code for that situation:<br>
        <br>
             () -> new ClassTransform() {<br>
                 boolean foundNM = false;<br>
        <br>
                 void accept(ClassBuilder b, ClassElement e) {<br>
                     switch (e) {<br>
                         case NestMembersAttribute a -> { transform
        a; foundNM = <br>
        true; }<br>
                         ... other transform stuff ...<br>
                     }<br>
                 }<br>
        <br>
                 void atEnd(ClassBuilder b) {<br>
                     if (!foundNM)<br>
                         builder.accept(NestMembersAttribute.of(...));<br>
                 }<br>
             }<br>
        <br>
        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.<br>
        <br>
        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.  <br>
        <br>
        <br>
        <br>
      </font></font><br>
    <div class="moz-cite-prefix">On 3/21/2023 11:38 PM, - wrote:<br>
    </div>
    <blockquote type="cite" cite="mid:CABe8uE1pm2WXJ8DjB-3Hbh=85Wv5T4sVUBdsetJ4ArLcOHvoSw@mail.gmail.com">
      <pre class="moz-quote-pre" wrap="">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
</pre>
    </blockquote>
    <br>
  </body>
</html>