Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Oct 24, 2025

Summary

This PR fixes issue #121066 where JIT optimizations (inlining, CSE, and redundant branch removal) were not respecting the side-effects of precise static constructors, leading to incorrect program behavior.

Problem

The CORINFO_HELP_INITCLASS and CORINFO_HELP_INITINSTCLASS JIT helpers were incorrectly marked as isPure = true in HelperCallProperties::init(). This caused the JIT to treat these helpers as having no side effects, allowing optimizations to eliminate or reorder static constructor calls. However, static constructors can have observable side effects (modifying static fields, I/O operations, etc.) that must be preserved.

Consider this reproduction case:

class MyPreciseInitClass<T>
{
    static MyPreciseInitClass()
    {
        preciseInitCctorsRun++;  // Side effect!
    }

    public static void TriggerCctorClass() { }
}

// With tiered compilation disabled
MyPreciseInitClass<int>.TriggerCctorClass();
// Expected: preciseInitCctorsRun == 1
// Actual: preciseInitCctorsRun == 0 (constructor was optimized away!)

Changes

src/coreclr/jit/utils.cpp

  • Removed isPure = true for CORINFO_HELP_INITCLASS and CORINFO_HELP_INITINSTCLASS cases
  • Added mutatesHeap = true to properly indicate these helpers modify program state

src/tests/JIT/Regression/JitBlue/Runtime_121066/

  • Added regression test that verifies static constructors are invoked exactly once per generic instantiation
  • Test validates the fix by checking that side effects (counter increments) occur as expected

Impact

This change ensures that the JIT compiler treats static constructor initialization helpers as having side effects, preventing incorrect optimizations that could eliminate or reorder these critical operations. The performance impact should be minimal since:

  1. Static constructors are already guarded by checks in most scenarios
  2. The mayRunCctor flag was already set (indicating potential side effects)
  3. This primarily affects edge cases with aggressive optimization

Fixes #121066

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • https://api.github.com/repos/dotnet/runtime/issues/121066
    • Triggering command: curl -s REDACTED (http block)

If you need me to access, download, or install something from one of these locations, you can either:

Original prompt

Fix #121066 isssue: in jit's utils.cpp in the function HelperCallProperties::init() find

            case CORINFO_HELP_INITCLASS:
            case CORINFO_HELP_INITINSTCLASS:

and remove isPure = true for it and add mutatesHeap = true.

Also, add the test case for it that was reported in #121066 (adapt it to be xunit test), similar to src/tests/JIT/Regression/JitBlue/Runtime_120792/Runtime_120792.cs (but with the issue id)


💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

…est case

Co-authored-by: EgorBo <523221+EgorBo@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix helper call properties for init class in JIT Fix #121066: Mark INITCLASS helpers as mutating heap to respect static constructor side-effects Oct 24, 2025
Copilot AI requested a review from EgorBo October 24, 2025 15:26
Copilot finished work on behalf of EgorBo October 24, 2025 15:26
@EgorBo
Copy link
Member

EgorBo commented Oct 24, 2025

5 methods affected in the diffs, looks like we no longer CSE something over the CLASS_INIT call, presumably, for a good reason.

@EgorBo EgorBo marked this pull request as ready for review October 24, 2025 16:07
Copilot AI review requested due to automatic review settings October 24, 2025 16:07
@EgorBo
Copy link
Member

EgorBo commented Oct 24, 2025

PTAL @AndyAyersMS @dotnet/jit-contrib

This comment was marked as resolved.

@EgorBo EgorBo requested a review from AndyAyersMS October 24, 2025 16:08
Copy link
Member

@AndyAyersMS AndyAyersMS left a comment

Choose a reason for hiding this comment

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

Can you open a follow up issue?

We should model these helpers the same way we model all the others and fix the logic in VN to add heap mutation when appropriate.

@EgorBo EgorBo enabled auto-merge (squash) October 26, 2025 12:32
@EgorBo
Copy link
Member

EgorBo commented Oct 26, 2025

@jkotas @AndyAyersMS any ideas if it meets the bar for backport to 9.0? It seems like explicit initclass calls are rare, normally, we trigger cctor via one of the STATICBASE helper calls

@EgorBo EgorBo merged commit 530271d into main Oct 26, 2025
121 checks passed
@jkotas jkotas deleted the copilot/fix-helpercallproperties-issue-121066 branch October 26, 2025 13:34
@jkotas
Copy link
Member

jkotas commented Oct 26, 2025

any ideas if it meets the bar for backport to 9.0?

Can this bug manifest as a tiered compilation behavior difference? (ie it works when called once, it breaks if when called hundred times). It would be my primary justification of the backport. Reliability bugs like that are always difficult to diagnose.

I would do proactive 10.0 backport only. Backport to 8.0/9.0 reactively only if we get customer report.

@AndyAyersMS
Copy link
Member

Seems like it could show up latently. Say a method avoids touching a class the first N times it is called, and then uses it, and by then the method is tiered up. Or it is called once and loops M times before touching the class, and by then it is running an OSR version.

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.

Side-effects of precise static constructors not respected by optimizations

5 participants