Skip to content

LTW generates invalid StackMapTable when weaving Kotlin suspend state-machine methods on JDK 21 #352

@gghost1

Description

@gghost1

Environment

  • JDK: 21
  • Kotlin: 2.2.x (Kotlin/JVM)
  • AspectJ: aspectjweaver 1.9.24, aspectjrt 1.9.24
  • Build tool: Gradle (Kotlin DSL), tests run with -javaagent:aspectjweaver.jar (LTW)

Problem

Load-time weaving with aspectjweaver fails (or produces bytecode that fails verification) when advising Kotlin suspend functions compiled into coroutine state machines.
The same setup works for “simple” suspend functions without a state machine (e.g., a single suspend call).

Minimal reproducer

A minimal Gradle Kotlin project.
It contains:

  • A custom annotation (e.g., @MyAnnotation) to match the pointcut.
  • An annotation-style aspect (@Aspect) with @Before, @AfterReturning, @AfterThrowing advices on execution(@MyAnnotation * *(..)).
  • A JUnit5 test using runTest.

Kotlin code (simplified):

@Test
fun test() = runTest { fun2() }

@MyAnnotation
suspend fun fun1() { coroutineContext }

@MyAnnotation
suspend fun fun2() {
    fun1()
    fun1() // removing this line makes the problem disappear
}

Observed behavior

The resulting woven class fails with either:

  • java.lang.VerifyError: Expecting a stackmap frame at branch target ... at class load time, or
  • an internal weaving error like AspectJ Internal Error: unable to add stackmap attributes ... with stack traces pointing to StackMapAdder / ASM Frame.merge (depending on the exact execution path).

Bytecode evidence (before/after)

I enabled LTW class dumping to capture woven classes. This produces _ajdump/_before/.../AspectTest.class and _ajdump/.../AspectTest.class.
Using javap -c -v, the before method contains a valid StackMapTable with multiple entries (Kotlin-generated state machine), while in the after version the control-flow is modified (try/catch + epilogue + gotos), and the resulting class appears to have missing or inconsistent stack map frames, leading to verification failure.
I can attach:

  • _ajdump/_before/.../*.class and _ajdump/.../*.class
  • javap -c -v outputs for fun2(Continuation) before and after weaving
  • Full Gradle project.

Expected behavior

LTW correctly recomputes/emits StackMapTable for the woven coroutine state machine methods, producing verifiable bytecode on JDK 21

Notes

This is not about advising Kotlin source code directly (Kotlin is compiled by kotlinc first). The issue is strictly about weaving already-compiled .class files generated by Kotlin for suspend state machines.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions