Working with attributes: experiences and suggestions
Rafael Winterhalter
rafael.wth at gmail.com
Thu Aug 29 11:05:00 UTC 2024
Hello,
I recently implemented a bridge between attributes in the Class File API
and ASM, which mostly succeeded, but I wanted to point out that this area
is one with the least compatibility. Making this production ready would
also require minor adjustments in the ASM API, but it seems like the team
there is open to those. I also understand that it's not a project goal to
replicate the ASM, but I assume that the ASM API is built upon actual use
cases and that a good compatibility will make migration easier for those
who aim for it.
To begin with, there are two minor incompatibilities that I do not think
will have a big impact, but which would be nice to fix:
- ASM exposes className, superClassName and interfaceNames from its
ClassReader. The Class File API only exposes className and superClassName.
One can still navigate through the attributed element to get hold of the
interface names unless attributing a record component info where the parent
is not exposed. This is mainly an inconvenience.
- ASM allows for translating constant pool indices to class file offsets.
In theory, one can read the entire class file using the Class File API's
ClassReader and offer the same translation, but I would want to avoid
manual parsing. The ASM API is offset based and only allows access to most
constants using an offset. The Class File API offers access for either
offset or index, but includes no possibility to translate. Maybe ASM could
however offer a way to access by either offset or index, too, and deprecate
the translation method. The Class File API is more convenient here and
there is no reason to ask a user to make conversions.
The more complex operation where I cannot currently succeed are attributes
on the code attribute. Unfortunately, those are the most common custom
attributes, and they often carry references to the code. Here I struggle to
use the Class File API altogether.
Normally, a custom attribute on code stores offsets to the byte code. In
some way, I want to add some information about a section of code. When
reading such an attribute I would read those offsets, which are typically
presented as labels. I think that from AttributeMapper::read, it should be
possible to tell the Class File API that labels should be inserted at given
positions. Those labels could then be discovered when walking through the
instructions. For example one could add a method "bciToLabel" method
somewhere. The resolved custom attribute could then only contain these
labels such that a user of the Class File API can match the labeled offset
to a segment in the code.
At the same time, AttributeMapper::write should contain a form of
"labelToBci" method such that (possibly altered) byte code offsets can be
stored back in the class file. Possibly getBci could be exposed on the
Label, too, maybe returning an OptionalInt to accommodate labels where the
offset is not yet bound.
The issue with this is that form of logic is only relevant to attributes on
the code attribute. ASM has itself a special handling of such attributes
where one overrides the isCodeAttribute method of org.ow2.asm.Attribute
class. When reading such an attribute, it is also passed additional
information. On reading, it is passed the beginning offset of the code
attribute itself and an array of labels that are included in the code.
There is however no way of inserting new labels as of today, something I
consider a lacking feature of ASM.
When writing such an attribute, ASM is including most data from the
CodeAttribute to which the attribute is written to. Personlly, I also think
that the Class File API should add the context to which an attribute is
written to as an argument, similar to when reading an attribute. It is
fully possible to write different data for example when adding an attribute
to a field, or to a method. Ideally, it should be possible to (lazily)
resolve previously written, different attributes from the target when
writing, to add contextual information.
Thanks! If you are curious how the back and forth mapping of ASM and JDK
attributes currently looks like, you can check this class:
https://github.com/raphw/asm-jdk-bridge/blob/main/src/main/java/codes/rafael/asmjdkbridge/AsmAttribute.java#L59
Best regards, Rafael
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/classfile-api-dev/attachments/20240829/ce1be8d8/attachment.htm>
More information about the classfile-api-dev
mailing list