[External] : Re: Mapping byte code offsets in custom code attributes

Adam Sotona adam.sotona at oracle.com
Mon Nov 11 20:21:11 UTC 2024


Hi Rafael,
Here is an example method:

    static void m() {
        int a = 1;
        int b = 2;
        a = 3;
        b = 4;
    }

This is a sample transformation manipulating line numbers and local variables:
        ClassFile.of().transformClass(clm, ClassTransform.transformingMethodBodies((cob, coe) -> {
            switch (coe) {
                case LineNumber ln ->
                    cob.lineNumber(ln.line() + 100); // change line numers
                case LocalVariable lv when lv.name().equalsString("a") ->
                    cob.localVariable(lv.slot(), "x", lv.typeSymbol(), cob.startLabel(), lv.endScope()); // rename var “a” to “x” and change its start scope
                case LocalVariable _ -> {} // drop var “b”
                default -> cob.with(coe);
            }
        }
        ).andThen(ClassTransform.transformingMethodBodies(CodeTransform.endHandler(cob -> cob
                .localVariable(1, "y", ConstantDescs.CD_int, cob.startLabel(), cob.endLabel()) // add var “y”
                .lineNumber(999))))); // add line number

And as you can see there are no custom attributes nor bytecode offset conversions necessary.

Yes, Class-File API contains several “raw” points where bytecode offsets are intentionally exposed to support specific use cases, however no one is obliged to use them.

I hope this finally addressed your questions.

Adam

From: Rafael Winterhalter <rafael.wth at gmail.com>
Date: Monday, 11 November 2024 at 18:59
To: Adam Sotona <adam.sotona at oracle.com>, classfile-api-dev <classfile-api-dev at openjdk.org>, Chen Liang <chen.l.liang at oracle.com>
Subject: Re: [External] : Re: Mapping byte code offsets in custom code attributes
(I realized that I did not reply-all and wanted to add the mailing list again. Some of the discussion can be found in the quotation below, if anyone is reading.)

I cannot describe a use case that goes beyond mere printing where I could work with BCIs in the context of a Class File API represented list of instructions. If I wanted to create a CharacterRangeTableAttribute, I would always have to resolve BCIs to labels. Why not let the AttributeMapper handle this translation consistently but require BCI as input to the factory method? To me, this seems more error prone and less type-safe.

Maybe I should ask the question differently: what led to a choice of using labels over BCIs when dealing with stack map frames, and for the runtime (in-)visible type annotations? I think the answer is that those are more convenient, despite that they are inlined. I cannot make sense that two groups of attributes are represented in two different ways, when labels are obviously more expressive. I get that type annotations and stack map frames might be more central attributes, where the others are more often used by power users. But also power users would benefit from the better abstraction, so I think this should be the target? If the answer is that there is no time to adjust the API, I wonder if one should avoid exposing those four other attributes until there is time, especially with Java 24 likely being less adopted compared to Java 25 where Oracle plans to offer LTS. I feel like exposing BCIs is premature, if labels could be used, and it would be a shame to lose the opportunity to use labels within these four info attributes. I already see the BCI factories and methods being deprecated in a future release, so why not aim for the best solution already today?

I understand that this API change is out of scope for JDK-8341274, but I would love to see a follow up change that adjusts those four interfaces to use labels and not BCIs, such that the Class File API is consistent. If possible within the release of Java 24, or Java 25 with the BCI methods not exposed before that.

Am Mo., 11. Nov. 2024 um 16:19 Uhr schrieb Adam Sotona <adam.sotona at oracle.com<mailto:adam.sotona at oracle.com>>:
Purpose of JDK-8341274 is to enable labels translation for custom attributes, it means other attributes than LineNumberTable, LocalVariableTable, LocalVariableTypeTable or CharacterRangeTable. It does not include any plan to remodel existing architecture.

What exact use case related to the above-mentioned attributes are you struggling with?

Thanks,
Adam

From: Rafael Winterhalter <rafael.wth at gmail.com<mailto:rafael.wth at gmail.com>>
Date: Monday, 11 November 2024 at 15:44
To: Adam Sotona <adam.sotona at oracle.com<mailto:adam.sotona at oracle.com>>
Subject: Re: [External] : Re: Mapping byte code offsets in custom code attributes
Hello,

As a goal of this conversation, I was hoping to give feedback on where I see limitations of the current API, something that resulted in JDK-8341274. As I wrote in previous emails on this list, I am evaluating it against a number of use cases, all of which use ASM as of today. When I speak of migration, I mean that users of ASM would take the class file API into use instead. This is why I hoped that JDK-8341274 could be concluded by using this API to remodel these four info attributes, to be consistent with TypeAnnotation and UninitializedVerificationTypeInfo. Clearly, if those attributes are using labels instead of BCIs, there should be a benefit of using labels exclusively? I had hoped that the Class File API could become as consistent as ASM in this regard.

I also understand that the mentioned info elements are streamlined with the code instruction API. But as the use of code generation has evolved upon ASM over many years, where attributes are not always generated at the same time as the attributed code, but later. Rather, one notes down BCIs as labels in the generated code and writes the attribute upon completion. In some cases, such logic can be rewritten to fit the streamlined model. But sometimes this is really hard. Neither the class file format, nor the class file API require that attributes on code are created simultaneously, so I was hoping that explicit BCIs could be removed from the public API altogether. Today, they only appear at four locations (LocalVariable, LocalVariableType, CharacterRange and LineNumber) throughout the entire Class File API. Anywhere else, BCIs are resolved as labels. I think changing that would add to the Class File APIs quality, consistency and usability, when working with these attributes, similar to how it is suggested to work with custom ones. I hoped I could argue that case before the API becomes final and this can no longer be changed.

Patching line numbers is indeed supported, if one reiterates over the code, but I would not call this a seamless solution in contrast to just writing that attribute after completing the code attribute, if this is what is desired.

Thanks, Rafael

Am Mo., 11. Nov. 2024 um 14:38 Uhr schrieb Adam Sotona <adam.sotona at oracle.com<mailto:adam.sotona at oracle.com>>:
Hi Rafael,
I’m not sure what is goal of this discussion. Let me answer your questions below.

From: Rafael Winterhalter <rafael.wth at gmail.com<mailto:rafael.wth at gmail.com>>


  *   What I do not understand is why this model should not be applied for LineNumberInfo, LocalVariableTypeInfo, LocalVariableInfo and CharacterRangeInfo?

LocalVariable, LocalVariableType, CharacterRange and LineNumber are pseudo instructions (code elements). As such they are integral part of the CodeModel and they are streamed and transformed with the instructions. LineNumberInfo, LocalVariableTypeInfo, LocalVariableInfo are just inner structure data holders of the corresponding attributes and they serve only to specific use cases requesting the raw values.



  *   Once a translation mechanism is in place, it should be straightforward to migrate?

I’m not sure what migration do you have in mind.



  *   What is the point of offering these attributes in a (public) API then, if not as ready for consumption?

There are regular consumers of the API, like for example javap.



  *   As I see it: Without labels, I would need to implement a custom mapper, for example for writing a custom LineNumberTableAttribute,

There are two aspects:

  1.  A custom LineNumberTable attribute mapper overriding the default one is not accepted by the API.
  2.  Implementation of a custom attribute similar to LineNumberTable attribute is supported and after JDK-8341274 the support will improve.



  *   if I wanted to patch line numbers after creating a method.

Patching line numbers is seamlessly supported. CodeTransform can freely change, add, and remove line numbers.


>From the context I understand you call for indirect translation of each (currently inline) LocalVariable, LocalVariableType, CharacterRange and LineNumber into a Label-parametrized pseudo instructions + corresponding LabelTargets. Such model has been rejected in the early Class-File API prototypes for significant negative performance impact.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/classfile-api-dev/attachments/20241111/7c7aa494/attachment-0001.htm>


More information about the classfile-api-dev mailing list