POC: JDK ClassModel -> ASM ClassReader

Rafael Winterhalter rafael.wth at gmail.com
Tue Jul 26 22:23:41 UTC 2022


Hi Brian,
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:
https://github.com/raphw/jdk-sandbox/tree/classfile-api-monad - I
integrated it in my writer bridge for ASM here:
https://github.com/raphw/asm-jdk-bridge/tree/writer-poc which is more or
less working for the majority of cases.

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.

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.

Best regards, Rafael

Am Mo., 25. Juli 2022 um 20:30 Uhr schrieb Brian Goetz <
brian.goetz at oracle.com>:

> 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.)
>
> 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.
>
>
> 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.)
>
> 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:
>
>  - 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.
>  - 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.)
>  - Expose implicitly partial APIs, such as throwing when you ask a
> question in the wrong mode.
>
> 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.
>
> 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.)
>
> 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.
>
>
> This is a good example of something that would only work on bound
> instructions, because the unbound ones are "stateless".
>
> 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.
>
>
> 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.
>
>
> Q: in this case, is it enough if only ClassBuilder has this option, or
>> do you need it for MethodBuilder and CodeBuilder as well?
>>
>
> Did you ever answer this question?
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/classfile-api-dev/attachments/20220727/d0659dc9/attachment-0001.htm>


More information about the classfile-api-dev mailing list