Skip to content

Avoid cctor check if we provably executed it - #131526

Open
MichalStrehovsky wants to merge 1 commit into
dotnet:mainfrom
MichalStrehovsky:initfld
Open

Avoid cctor check if we provably executed it#131526
MichalStrehovsky wants to merge 1 commit into
dotnet:mainfrom
MichalStrehovsky:initfld

Conversation

@MichalStrehovsky

Copy link
Copy Markdown
Member

For this program and the S method:

public class C2
{
    [MethodImpl(MethodImplOptions.NoInlining)]
    public string S() => d + s;

    public static readonly string s;

    private string d = "d";

    static C2() => s = Helpers.NoInline("s");
}

Before:

G_M34299_IG01:  ;; offset=0x0000
       push     rbx
       sub      rsp, 32
                                                ;; size=5 bbWeight=1 PerfScore 1.25
G_M34299_IG02:  ;; offset=0x0005
       mov      rbx, gword ptr [rcx+0x08]
       lea      rax, [(reloc 0x420b68)]
       cmp      qword ptr [rax-0x08], 0
       jne      SHORT G_M34299_IG05
                                                ;; size=18 bbWeight=1 PerfScore 5.50
G_M34299_IG03:  ;; offset=0x0017
       mov      rdx, qword ptr [(reloc 0x425630)]
       mov      rdx, gword ptr [rdx+0x08]
       mov      rcx, rbx
       call     System.String:Concat(System.String,System.String):System.String
       nop
                                                ;; size=20 bbWeight=1 PerfScore 5.50
G_M34299_IG04:  ;; offset=0x002B
       add      rsp, 32
       pop      rbx
       ret
                                                ;; size=6 bbWeight=1 PerfScore 1.75
G_M34299_IG05:  ;; offset=0x0031
       call     CORINFO_HELP_READYTORUN_GCSTATIC_BASE
       jmp      SHORT G_M34299_IG03
                                                ;; size=7 bbWeight=0 PerfScore 0.00

After:

       sub      rsp, 40
                                                ;; size=4 bbWeight=1 PerfScore 0.25
G_M34299_IG02:  ;; offset=0x0004
       mov      rcx, gword ptr [rcx+0x08]
       mov      rdx, qword ptr [(reloc 0x425608)]
       mov      rdx, gword ptr [rdx+0x08]
       call     System.String:Concat(System.String,System.String):System.String
       nop
                                                ;; size=21 bbWeight=1 PerfScore 7.25
G_M34299_IG03:  ;; offset=0x0019
       add      rsp, 40
       ret

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 3 pipeline(s).
13 pipeline(s) were filtered out due to trigger conditions.
There may be pipelines that require an authorized user to comment /azp run to run.

@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @agocke, @dotnet/ilc-contrib
See info in area-owners.md if you want to be subscribed.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR updates the AOT RyuJit JIT-EE interface to use initClass analysis (rather than a coarse “has lazy cctor” check) when reporting static field access requirements, enabling the JIT to elide redundant class-constructor checks when initialization is already provably satisfied (e.g., instance-method cases).

Changes:

  • Refactors initClass in the shared JitInterface to add a FieldDesc/MethodDesc overload and a handle-based wrapper.
  • Updates ILCompiler.RyuJit getFieldInfo to consult initClass and (a) set CORINFO_FLG_FIELD_INITCLASS only when needed and (b) choose relocatable static base access when init is not required.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs Adds an overload to run initClass logic directly on FieldDesc/MethodDesc, with a wrapper for handle-based entrypoints.
src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs Uses initClass results in getFieldInfo to avoid unnecessary cctor triggering / helper usage for static field accesses.

if (_compilation.HasLazyStaticConstructor(field.OwningType))
if (initResult != CorInfoInitClassResult.CORINFO_INITCLASS_NOT_REQUIRED)
{
fieldFlags |= CORINFO_FIELD_FLAGS.CORINFO_FLG_FIELD_INITCLASS;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

CORINFO_FLG_FIELD_INITCLASS means "initClass has to be called before accessing the field". We should not need to optimize it by calling initClass proactively before the flag is set. The JIT is going to call initClass when CORINFO_FLG_FIELD_INITCLASS is set.

@MichalPetryka

Copy link
Copy Markdown
Contributor

Worth noting that this can change behaviour for calling instance methods with null this, but ECMA explicitly permits skipping cctor then (still there could be code relying on it being executed).

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants