POC: JDK ClassModel -> ASM ClassReader
Brian Goetz
brian.goetz at oracle.com
Mon Jul 25 18:30:47 UTC 2022
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/20220725/a705cb0c/attachment.htm>
More information about the classfile-api-dev
mailing list