Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

MichalStrehovsky
Copy link
Member

Marking fields readonly has a couple benefits:

  • Codegen can assume the value doesn't change and can inline the values into code.
  • In the static constructor interpreter, we allow reading readonly fields of other classes. So class A { public static int X = 123 } class B { static int Y = A.X } - A can be preinitialized at compile time, but B cannot. However: class A { public static readonly int X = 123 } class B { static int Y = A.X } both A and B can preinitialize at compile time.

In this PR, I'm adding infrastructure to collect information about field writes during whole program analysis. This collects information about fields that are effectively read-only. Then during compilation, we use this data instead of the IsInitOnly metadata. The big advantage of this approach (as opposed to e.g. a Roslyn analyzer) is that we look at the app after trimming - some fields might be writable, but if we discarded the code that writes them, they're read only.

This is also a correctness fix - the compiler would previously assume preinitializing instances of classes with all-readonly instance fields is safe, but one can set them with reflection and this would lead to a crash in the write barrier. Not that anyone should be reflection-setting readonly fields outside of deserialization scenarios.

Cc @dotnet/ilc-contrib

@ghost
Copy link

ghost commented Oct 3, 2023

Tagging subscribers to this area: @agocke, @MichalStrehovsky, @jkotas
See info in area-owners.md if you want to be subscribed.

Issue Details

Marking fields readonly has a couple benefits:

  • Codegen can assume the value doesn't change and can inline the values into code.
  • In the static constructor interpreter, we allow reading readonly fields of other classes. So class A { public static int X = 123 } class B { static int Y = A.X } - A can be preinitialized at compile time, but B cannot. However: class A { public static readonly int X = 123 } class B { static int Y = A.X } both A and B can preinitialize at compile time.

In this PR, I'm adding infrastructure to collect information about field writes during whole program analysis. This collects information about fields that are effectively read-only. Then during compilation, we use this data instead of the IsInitOnly metadata. The big advantage of this approach (as opposed to e.g. a Roslyn analyzer) is that we look at the app after trimming - some fields might be writable, but if we discarded the code that writes them, they're read only.

This is also a correctness fix - the compiler would previously assume preinitializing instances of classes with all-readonly instance fields is safe, but one can set them with reflection and this would lead to a crash in the write barrier. Not that anyone should be reflection-setting readonly fields outside of deserialization scenarios.

Cc @dotnet/ilc-contrib

Author: MichalStrehovsky
Assignees: MichalStrehovsky
Labels:

area-NativeAOT-coreclr

Milestone: -

@MichalStrehovsky
Copy link
Member Author

/azp run runtime-nativeaot-outerloop

@azure-pipelines
Copy link

Azure Pipelines successfully started running 1 pipeline(s).

Copy link
Member

@jkotas jkotas left a comment

Choose a reason for hiding this comment

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

Nice!

@MichalStrehovsky MichalStrehovsky merged commit 85d0169 into dotnet:main Oct 6, 2023
@MichalStrehovsky MichalStrehovsky deleted the readonlyfields branch October 6, 2023 07:54
@ghost ghost locked as resolved and limited conversation to collaborators Nov 5, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants