<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=us-ascii">
<style type="text/css" style="display:none;"> P {margin-top:0;margin-bottom:0;} </style>
</head>
<body dir="ltr">
<div class="elementToProof" style="font-family: Aptos, Aptos_EmbeddedFont, Aptos_MSFontService, Calibri, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
Hi Rafael,</div>
<div class="elementToProof" style="font-family: Aptos, Aptos_EmbeddedFont, Aptos_MSFontService, Calibri, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
I believe this is due to a misunderstanding with how ClassFile API labels work.  A ClassFile API label models an insertion point represented by a BCI; so in your example, the bound label should be located right before the new instruction, so that the next immediately
 executed instruction would be the new instruction.  This is like how the labels for control flows work.</div>
<div class="elementToProof" style="font-family: Aptos, Aptos_EmbeddedFont, Aptos_MSFontService, Calibri, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
<br>
</div>
<div class="elementToProof" style="font-family: Aptos, Aptos_EmbeddedFont, Aptos_MSFontService, Calibri, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
Unfortunately, I understand this is distinct from the ASM model - ASM visitor model treats this as if this is a tiny tree structure and considers a type annotation as a subsidiary of an instruction, and this brings challenges to porting the implementations. 
 Here's some context: we ClassFile API developers long believed that type annotations interact poorly with class file transformations because of hard-to-track arbitrary references such as interface indices, and thus we did not integrate it as a part of the
 ClassFile API code streaming model, and we drops type annotation attributes in transformations by the attribute stability settings.</div>
<div class="elementToProof" style="font-family: Aptos, Aptos_EmbeddedFont, Aptos_MSFontService, Calibri, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
<br>
</div>
<div class="elementToProof" style="font-family: Aptos, Aptos_EmbeddedFont, Aptos_MSFontService, Calibri, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
Regards,</div>
<div class="elementToProof" style="font-family: Aptos, Aptos_EmbeddedFont, Aptos_MSFontService, Calibri, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
Chen Liang</div>
<div id="appendonsend"></div>
<hr style="display:inline-block;width:98%" tabindex="-1">
<div id="divRplyFwdMsg" dir="ltr"><font face="Calibri, sans-serif" style="font-size:11pt" color="#000000"><b>From:</b> classfile-api-dev <classfile-api-dev-retn@openjdk.org> on behalf of Rafael Winterhalter <rafael.wth@gmail.com><br>
<b>Sent:</b> Saturday, November 9, 2024 3:09 PM<br>
<b>To:</b> classfile-api-dev <classfile-api-dev@openjdk.org><br>
<b>Subject:</b> Offset error when writing type annotations on NEW instructions</font>
<div> </div>
</div>
<div>
<div dir="ltr">
<div>With the most recent build of JDK 24, I discover one test failure in my test suite when comparing with ASM (<a href="https://github.com/raphw/asm-jdk-bridge">https://github.com/raphw/asm-jdk-bridge</a>): Any type annotation that is added to a "new" instruction
 is added to the subsequent instruction instead. This might irritate parsers as the label will point to an instruction that cannot normally be annotated, as NEW is normally followed by DUP.</div>
<div><br>
</div>
<div>I created a reproducers that compares a javac compiled class and one that is created with the class file API. The error is likely in the attribute mapper's write method as I cannot reproduce it when testing a class file reader using the class file API
 compared to ASM. The reproducer is as follows and is visualized in the first line of each of the two representations where the correct byte code offset is 0, not 3 as the annotation is added to the first instruction in the method:</div>
<div><br>
</div>
<div>
<div style="background-color:rgb(30,31,34); color:rgb(188,190,196)">
<pre style="font-family:"JetBrains Mono",monospace; font-size:9.8pt"><br><span style="color:rgb(207,142,109)">import </span>java.io.InputStream;<br><span style="color:rgb(207,142,109)">import </span>java.lang.annotation.ElementType;<br><span style="color:rgb(207,142,109)">import </span>java.lang.annotation.<span style="color:rgb(179,174,96)">Retention</span>;<br><span style="color:rgb(207,142,109)">import </span>java.lang.annotation.RetentionPolicy;<br><span style="color:rgb(207,142,109)">import </span>java.lang.annotation.<span style="color:rgb(179,174,96)">Target</span>;<br><span style="color:rgb(207,142,109)">import </span>java.lang.classfile.*;<br><span style="color:rgb(207,142,109)">import </span>java.lang.classfile.attribute.RuntimeVisibleTypeAnnotationsAttribute;<br><span style="color:rgb(207,142,109)">import </span>java.lang.classfile.instruction.LineNumber;<br><span style="color:rgb(207,142,109)">import </span>java.lang.classfile.instruction.LocalVariable;<br><span style="color:rgb(207,142,109)">import </span>java.lang.constant.ClassDesc;<br><span style="color:rgb(207,142,109)">import </span>java.lang.constant.MethodTypeDesc;<br><span style="color:rgb(207,142,109)">import </span>java.util.List;<br><br><span style="color:rgb(207,142,109)">public class </span>TypeAnnotationSample {<br><br>    <span style="color:rgb(207,142,109)">void </span><span style="color:rgb(86,168,245)">m</span>() {<br>        <span style="color:rgb(207,142,109)">new </span><span style="color:rgb(179,174,96)">@A </span>Object();<br>    }<br><br>    <span style="color:rgb(207,142,109)">public static void </span><span style="color:rgb(86,168,245)">main</span>(String[] args) <span style="color:rgb(207,142,109)">throws </span>Exception {<br>        <span style="color:rgb(207,142,109)">byte</span>[] compiled;<br>        <span style="color:rgb(207,142,109)">try </span>(InputStream inputStream = TypeAnnotationSample.<span style="color:rgb(207,142,109)">class</span>.getClassLoader().getResourceAsStream(<br>            TypeAnnotationSample.<span style="color:rgb(207,142,109)">class</span>.getName().replace(<span style="color:rgb(106,171,115)">'.'</span>, <span style="color:rgb(106,171,115)">'/'</span>) + <span style="color:rgb(106,171,115)">".class"<br></span><span style="color:rgb(106,171,115)">        </span>)) {<br>            compiled = inputStream.readAllBytes();<br>        }<br>        <span style="font-style:italic">print</span>(compiled);<br>        System.<span style="color:rgb(199,125,187); font-style:italic">out</span>.println(<span style="color:rgb(106,171,115)">"-----"</span>);<br>        <span style="color:rgb(207,142,109)">byte</span>[] created = ClassFile.<span style="font-style:italic">of</span>().build(ClassDesc.<span style="font-style:italic">of</span>(<span style="color:rgb(106,171,115)">"Synthetic"</span>), classBuilder -> {<br>            classBuilder.withMethod(<span style="color:rgb(106,171,115)">"m"</span>, MethodTypeDesc.<span style="font-style:italic">of</span>(<span style="color:rgb(207,142,109)">void</span>.<span style="color:rgb(207,142,109)">class</span>.describeConstable().orElseThrow()), <span style="color:rgb(42,172,184)">0</span>, methodBuilder -> {<br>                methodBuilder.withCode(codeBuilder -> {<br>                    codeBuilder.new_(Object.<span style="color:rgb(207,142,109)">class</span>.describeConstable().orElseThrow());<br>                    Label label = codeBuilder.newBoundLabel();<br>                    codeBuilder.with(RuntimeVisibleTypeAnnotationsAttribute.<span style="font-style:italic">of</span>(TypeAnnotation.<span style="font-style:italic">of</span>(<br>                            TypeAnnotation.TargetInfo.<span style="font-style:italic">ofNewExpr</span>(label),<br>                            List.<span style="font-style:italic">of</span>(),<br>                            Annotation.<span style="font-style:italic">of</span>(<span style="color:rgb(179,174,96)">A</span>.<span style="color:rgb(207,142,109)">class</span>.describeConstable().orElseThrow())<br>                    )));<br>                    codeBuilder.dup()<br>                            .invokespecial(Object.<span style="color:rgb(207,142,109)">class</span>.describeConstable().orElseThrow(), <span style="color:rgb(106,171,115)">"<init>"</span>, MethodTypeDesc.<span style="font-style:italic">of</span>(<span style="color:rgb(207,142,109)">void</span>.<span style="color:rgb(207,142,109)">class</span>.describeConstable().orElseThrow()))<br>                            .pop()<br>                            .return_();<br>                });<br>            });<br>        });<br>        <span style="font-style:italic">print</span>(created);<br>    }<br><br>    <span style="color:rgb(207,142,109)">private static void </span><span style="color:rgb(86,168,245)">print</span>(<span style="color:rgb(207,142,109)">byte</span>[] classFile) {<br>        ClassModel classModel = ClassFile.<span style="font-style:italic">of</span>().parse(classFile);<br>        MethodModel methodModel = classModel.methods().stream()<br>                .filter(element -> element.methodName().equalsString(<span style="color:rgb(106,171,115)">"m"</span>))<br>                .findFirst()<br>                .orElseThrow();<br>        CodeModel codeModel = methodModel.code().orElseThrow();<br>        codeModel.elementStream().forEach(element -> {<br>            <span style="color:rgb(207,142,109)">switch </span>(element) {<br>                <span style="color:rgb(207,142,109)">case </span>LocalVariable _ -> { }<br>                <span style="color:rgb(207,142,109)">case </span>LineNumber _ -> { }<br>                <span style="color:rgb(207,142,109)">case </span>RuntimeVisibleTypeAnnotationsAttribute a -> System.<span style="color:rgb(199,125,187); font-style:italic">out</span>.println(a.annotations().stream()<br>                        .map(x -> x.annotation()<br>                                + <span style="color:rgb(106,171,115)">"@" </span>+ x.targetPath()<br>                                + <span style="color:rgb(106,171,115)">"/" </span>+ ((TypeAnnotation.OffsetTarget) x.targetInfo()).target())<br>                        .toList());<br>                <span style="color:rgb(207,142,109)">default </span>-> System.<span style="color:rgb(199,125,187); font-style:italic">out</span>.println(element);<br>            }<br>        });<br>    }<br><br>    <span style="color:rgb(179,174,96)">@Retention</span>(RetentionPolicy.<span style="color:rgb(199,125,187); font-style:italic">RUNTIME</span>)<br>    <span style="color:rgb(179,174,96)">@Target</span>(ElementType.<span style="color:rgb(199,125,187); font-style:italic">TYPE_USE</span>)<br>    @<span style="color:rgb(207,142,109)">interface </span><span style="color:rgb(179,174,96)">A </span>{<br>    }<br>}</pre>
</div>
</div>
<div><br>
</div>
<div>I think that the attribute mapper must subtract the bytes of the instruction as it is currently adding the bytes at the end of the instruction, not at its beginning. ASM and javac set the annotation offset to the beginning of the statement, so I understand
 that this should be the right approach.</div>
<div><br>
</div>
<div>Thanks, Rafael<br>
</div>
</div>
</div>
</body>
</html>