Classfile type annotation for CAST expressions

Archie Cobbs archie.cobbs at gmail.com
Mon Nov 10 19:45:03 UTC 2025


Could someone help me confirm whether the following behavior is incorrect,
or just under-specified?

Consider this code:

import java.lang.annotation.*;

public class DoubleCast {
    DoubleCast(Object o) {
        o = (DoubleCast & @Anno Runnable)o;
    }
}

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE_USE)
@interface Anno { }

There is an @Anno type annotation on the second class in the cast
expression (Runnable), so we expect to find that noted in the
RuntimeVisibleTypeAnnotations classfile attribute. Because the cast
involves an intersection type, the bytecode will have two CHECKCAST
instructions, as shown in the javap output:

  DoubleCast(java.lang.Object);
    descriptor: (Ljava/lang/Object;)V
    flags: (0x0000)
    Code:
      stack=1, locals=2, args_size=2
         0: aload_0
         1: invokespecial #1                  // Method
java/lang/Object."<init>":()V
         4: aload_1
         5: checkcast     #7                  // class java/lang/Runnable
         8: checkcast     #9                  // class DoubleCast
        11: astore_1
        12: return
      LineNumberTable:
        line 3: 0
        line 4: 4
        line 5: 12
      RuntimeVisibleTypeAnnotations:
        0: #15(): CAST, offset=8, type_index=1
          Anno

Note that the bytecode offset in the attribute points to the CHECKCAST
instruction associated with the first cast type (DoubleCheckcast), not the
second, annotated type (Runnable), even though the type_index is correctly
pointing to the second type (Runnable).

I've also seen examples where the two CHECKCAST instructions are emitted in
the reverse order; in those cases, the same thing happens, i.e., offset
points to the first CHECKCAST to DoubleCheckcast instead of the second
CHECKCAST to Runnable.

The JLS specifies only that offset refers to "the bytecode instruction
corresponding to the cast expression", which is ambiguous because for an
intersection cast there are multiple such bytecodes. But even if you tried
to read that generously as "the first bytecode instruction corresponding to
the cast expression" then the example above would still be incorrect.

In any case, as things stand now it seems impossible to correctly identify
which type has the annotation: even if you look at the type_index there's
no guarantee that the order of the CHECKCAST instructions matches the order
in the source code, and even if there were such a guarantee, because the
bytecode offset is wrong, you'd be counting from the wrong offset.

Behavior confirmed on 17, 25, & 26.

Thanks,
-Archie

-- 
Archie L. Cobbs
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/compiler-dev/attachments/20251110/d31a6db5/attachment.htm>


More information about the compiler-dev mailing list