<div dir="ltr"><div>Hi Brian,</div><div>As for your question about the "open class writer": yes, I would need this for everything that is modelled as a visitor in ASM. I created a proof of concept here where this is shown: <a href="https://github.com/raphw/jdk-sandbox/tree/classfile-api-monad">https://github.com/raphw/jdk-sandbox/tree/classfile-api-monad</a> - I integrated it in my writer bridge for ASM here: <a href="https://github.com/raphw/asm-jdk-bridge/tree/writer-poc">https://github.com/raphw/asm-jdk-bridge/tree/writer-poc</a> which is more or less working for the majority of cases.</div><div><br></div><div>I agree with your conclusion about the stack map API. It would also be nice to opt-out on a per-method basis. With ASM, this has sometimes been limited to not being able to compute frames only for certain methods that would require to chain ASM-reader-writer chains. We had discussed a potential solution on the thread about functionality I lack to fully complete my writer adoption.</div><div><br></div><div>As for attributes: Ideally I would like to see that the AttributeMapper's by Attributes would allow me to write an attribute to a ConstantPool interface that I can implement myself. If I meet an attribute that JDK knows, I would like to simply pipe it to ASM's ClassWriter where that writer represents the targeted constant pool, rather than the JDK one. Maybe it could accept a form of reduced BufWriter as an interface that is not sealed? This would allow for a use against a different sink than a JDK class writer. This would make these partial byte-getters unneeded as the raw bytes are indeed less valuable if one could write a constant-pool-aware representation of that byte array to a sink.<br></div><div><br></div><div>Best regards, Rafael<br></div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">Am Mo., 25. Juli 2022 um 20:30 Uhr schrieb Brian Goetz <<a href="mailto:brian.goetz@oracle.com">brian.goetz@oracle.com</a>>:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">

  
  <div>
    Going through some old messages after vacation.  Not sure if I
    responded to any of these or not, so forgive me if I've said this
    already (or something contradictory.)<br>
    <br>
    <blockquote type="cite">
      <div dir="ltr">
        <div>Thanks for merging my patches, the class reader API works
          more or less equivalent to the ASM version. The one thing I
          have not working so far are attributes that the JDK knows but
          ASM does not. I was trying to implement the "contents" method
          upwards, but this is difficult with the unbound attributes as
          they normally require a BufWriter which in turn needs a
          ConstantPoolBuilder. Somehow, I need to pipe the constant
          resolution to ASM which cannot be done without unsealing some
          interfaces. I will try to prototype a solution here, too, but
          I wanted to get the writer working first.</div>
      </div>
    </blockquote>
    <br>
    This raises a more general question, which deserves a little bit of
    discussion.  For nearly every entity, there is a bound and unbound
    implementation.  The bound implementation is tied to a segment of a
    byte[] for a complete classfile; the unbound implementation can be
    considered a "deferred" implementation, and is disconnected from a
    constant pool.  The deferred implementation will eventually get
    written to a BufWriter which is bound to a constant pool. 
    Similarly, when building, there are "direct" builders (who are
    accumulating various byte[] to write to the classfile) and
    "buffered" builders (which accumulate lists of elements.)  <br>
    <br>
    There are some questions about entities that can only be answered by
    "bound" entities or "direct" builders, such as "what's the current
    BCI" or "give me the bytes of this attribute."  We have several
    choices here, none great:<br>
    <br>
     - Only expose APIs that can be satisfied by both implementations. 
    This means you don't get to ask questions like "what's the current
    BCI".  Seems unfortunate.<br>
     - Expose explicitly partial APIs, such as accessors returning
    Optional.  This makes it clear that you might not get an answer, but
    may annoy users as it is not always obvious that the question is
    partial (buffered builders, used when chaining transforms, are a
    non-obvious concept.)<br>
     - Expose implicitly partial APIs, such as throwing when you ask a
    question in the wrong mode.  <br>
    <br>
    We've been steering towards the third, on the theory/hope that it
    will only be natural to ask the question in the cases when we can
    actually answer.  This theory has been working out well so far,
    though this could simply be lack of imagination on our part.  <br>
    <br>
    Under the third option, we'd move the contents() method to the base
    BoundAttribute class, and have the unbound classes throw "sorry, I
    can't answer that right now."  This is arguably reasonable because
    you are much more likely to ask for the bytes of an attribute you've
    read from a classfile, than one you've just yourself asked to have
    written to a classfile.  Where this might fall down is deep in a
    transform chain, where an earlier stage might replace a bound
    attribute with an unbound one (say, dropping an Exception from the
    MethodExceptions attribute.) <br>
    <br>
    <blockquote type="cite">
      <div dir="ltr">
        <div>For the type annotations on instructions: Would it be an
          option to add "getVisibleAnnotations" and
          "getInvisibleAnnotations" to the relevant CodeElement types?
          This way, I could for example query the "ExceptionCatch" value
          for its annotations.
          <br>
        </div>
      </div>
    </blockquote>
    <br>
    This is a good example of something that would only work on bound
    instructions, because the unbound ones are "stateless".  <br>
    <br>
    <blockquote type="cite">
      <div dir="ltr">
        <div>
        </div>
        <div>StackMapFrames could on the other hand just be added at
          their position in the CodeElement iteration to receive them
          where they become relevant. This way, one would not need to
          keep track of the current offset. This would also allow for an
          easier write model where ASM does not allow you to know the
          offset of a stack map. I assume that the current model is very
          much modeled after the needs of the javap tool. Ideally, the
          frame objects would be reduced to the information that is
          contained in a class file and the consumer could track
          implicit information such as the "effective" stack and locals.</div>
      </div>
    </blockquote>
    <br>
    If we dispense stack map frames as part of the CodeElement
    iteration, users will assume that they can make their own stack map
    frames and send them downstream to the builder too (the whole model
    of transforms is based on flatmapping the stream of elements.)  It
    seems more likely that this will cause problems than will help.  <br>
    <br>
    <blockquote type="cite"><br>
      <div class="gmail_quote">
        <blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
          Q: in this case, is it enough if only ClassBuilder has this
          option, or <br>
          do you need it for MethodBuilder and CodeBuilder as well?<br>
        </blockquote>
      </div>
    </blockquote>
    <br>
    Did you ever answer this question? <br>
  </div>

</blockquote></div>