Skip to content

Scoverage: do not instrument methods that have too large bodies#25629

Open
anatoliykmetyuk wants to merge 2 commits intoscala:mainfrom
anatoliykmetyuk:fix/scoverage-method-too-large
Open

Scoverage: do not instrument methods that have too large bodies#25629
anatoliykmetyuk wants to merge 2 commits intoscala:mainfrom
anatoliykmetyuk:fix/scoverage-method-too-large

Conversation

@anatoliykmetyuk
Copy link
Copy Markdown
Contributor

While instrumenting trees, coverage instrumentation increases their size. There is a fundamental limit of 64KB on method body size on JVM. When a large method is instrumented, it can exceed this limit and cause compilation to fail with Method too large.

This PR opts out coverage instrumentation for oversized DefDef and ValDef bodies, the size of which is greater than 3000. The rationale for the number being that the per-statement overhead of Invoker.invoked() is ~15 bytes, and roughly half of the tree nodes in a large body would each add that overhead. So, 3000 nodes would be about 24KB of added instrumentation bytecode.

If a method is opted out from coverage due to size, a warning is emitted.

How much have you relied on LLM-based tools in this contribution?

Moderately.

How was the solution tested?

  • Reproduced the five failing tests individually with coverage before the fix
  • Re-ran the same five tests with coverage after the fix and confirmed they pass
  • Ran sbt --client testCompilation

Coverage instrumentation adds ~15 bytes per statement via
Invoker.invoked() calls. For very large method bodies or val
initializers (e.g., thousands of method calls or huge array literals),
this can push the generated bytecode over the JVM's 64KB method size
limit.

Skip coverage instrumentation for DefDefs and ValDefs whose RHS
tree exceeds 3000 nodes. These bodies are left uninstrumented to
prevent "Method too large" emission errors, while the rest of the
compilation unit is instrumented normally.

Fixes coverage compilation for: large2.scala, i7034.scala,
i20521.scala, bridges.scala, t10594.scala.
@anatoliykmetyuk anatoliykmetyuk marked this pull request as ready for review March 26, 2026 12:21
Copy link
Copy Markdown
Contributor

@SolalPirelli SolalPirelli left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like a reasonable workaround; for posterity, is there some underlying reason why this skip logic can't be moved to coverage generation so it checks the actual covered size?

@anatoliykmetyuk
Copy link
Copy Markdown
Contributor Author

Thank you for the review @SolalPirelli !

The reason for using a heuristic approach is that we don't know the emitted bytecode's actual size until the backend phase at the very end of the compilation chain. Coverage instrumentation is a tree transformation step that happens much earlier. If we did the check at backend, there would be no trivial, unintrusive way to revert the instrumentation step.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants