Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow GlobalizationMode.Invariant = false to be substituted by the trimmer. #47999

Merged
merged 1 commit into from
Feb 9, 2021
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
</type>
<type fullname="System.Globalization.GlobalizationMode">
<method signature="System.Boolean get_Invariant()" body="stub" value="true" feature="System.Globalization.Invariant" featurevalue="true" />
<method signature="System.Boolean get_Invariant()" body="stub" value="false" feature="System.Globalization.Invariant" featurevalue="false" />
Copy link
Member

Choose a reason for hiding this comment

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

Are there other cases like this? I'm wondering whether we need more cases of handling both the true and false values, and if so, if there's a more general feature needed here, where the linker sees a line like:

<method signature="System.Boolean get_Invariant()" body="stub" feature="System.Globalization.Invariant" featurevalue="true" />

and automatically propagates featurevalue to value, or something like that.

Copy link
Member

Choose a reason for hiding this comment

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

I had proposed this in chat to @eerhardt the other day since it means we are potentially leaving behind bits of "unused" code that are statically known to only be true/false and therefore have no side effects.

dotnet/linker#1106 (comment) is a related example where just leaving the get_IsSupported() methoods can lead to larger downstream impact due to inheritance chains.

Copy link
Member Author

Choose a reason for hiding this comment

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

In all our existing feature switches, only 1 value will trim any substantial piece of code. For Invariant, I wasn't aware how much unnecessary code was still being rooted for the default setting. I thought only Invariant=true would trim a decent amount of code.

But I can imagine this being beneficial in other feature switches in the future.

cc @marek-safar @vitek-karas @sbomer - thoughts?

Copy link
Member

Choose a reason for hiding this comment

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

A related bit is that even needing to hardcode get_Invariant and others seems potentially unnecessary in certain cases

One would expect the linker could recognize the general pattern of static readonly bool s_name = AppContext.TryGetSwitch("", out bool result) ? result : default (or others) and that we wouldn't need to hardcode a table of substitutions outside of more complicated scenarios.
It, plus knowing that static readonly <primitive> name = value can't change after being set seem like generally good things to recognize as they can lead to later downstream optimizations and therefore trimming opportunities

Copy link
Member

Choose a reason for hiding this comment

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

If it's common we could make syntax which would be able to substitute the value directly from the feature value. Note that even boolean features have 3 values: true, false, not-set. I assume the "not-set" would mean no substitution (unless the defaultfeaturevalue is used).

If this is the only place right now, it's probably not worth it though.

Copy link
Member Author

Choose a reason for hiding this comment

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

One would expect the linker could recognize the general pattern

That could work for other cases, but it doesn't work for this case:

internal static bool Invariant { get; } = GetGlobalizationInvariantMode();
internal static bool UseNls => false;
private static bool GetGlobalizationInvariantMode()
{
bool invariantEnabled = GetInvariantSwitchValue();
if (!invariantEnabled)
{
if (TryGetAppLocalIcuSwitchValue(out string? icuSuffixAndVersion))
{
LoadAppLocalIcu(icuSuffixAndVersion);
}
else
{
int loaded = Interop.Globalization.LoadICU();
if (loaded == 0 && !OperatingSystem.IsBrowser())
{
string message = "Couldn't find a valid ICU package installed on the system. " +
"Set the configuration flag System.Globalization.Invariant to true if you want to run with no globalization support.";
Environment.FailFast(message);
}
// fallback to Invariant mode if LoadICU failed (Browser).
return loaded == 0;
}
}
return invariantEnabled;
}

</type>
<type fullname="System.LocalAppContextSwitches">
<method signature="System.Boolean get_EnableUnsafeUTF7Encoding()" body="stub" value="false" feature="System.Text.Encoding.EnableUnsafeUTF7Encoding" featurevalue="false" />
Expand Down