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

Introduces a peverify-compat feature flag #21269

Merged
merged 6 commits into from
Aug 8, 2017

Conversation

VSadov
Copy link
Member

@VSadov VSadov commented Aug 2, 2017

In some scenarios we have a choice of emitting faster code that is typesafe, but not formally verifiable vs. less efficient but verifiable code.

The most common occurrence is around accessing readonly fields of structs. If the intent is only to read, then we could just get a field reference and read to it.
However verification rules do not make distinction when reference is used only to read and require that intermediate copy of the field value be made.

The flag allows suppressing peverify violations, where possible, typically at the cost of introducing intermediate copying.

VSadov added 3 commits August 1, 2017 15:01
- Made readonly fields homeless outside the constructor when flag is set.
@tannergooding
Copy link
Member

@VSadov, so the default will be faster unverifiable code, but there will be an option to enable the slower verifiable code, correct?

Is this a case where we could get peverify updated to have knowledge about 'readonly' structs/fields?

@VSadov
Copy link
Member Author

VSadov commented Aug 2, 2017

@tannergooding - peverify as a tool is a bit of deadend at the moment.
It has too many assumptions about desktop .NET and dependencies/coupling with JIT internal implementation of the rules. Not all JITs do it the same way, so behavior may vary and difficult to change without changing JIT. Some JITs do not want to be in verification business at all...

The most likely vehicle for smarter rules is this, once it is more mature: https://github.com/dotnet/corert/tree/master/src/ILVerify

@VSadov
Copy link
Member Author

VSadov commented Aug 2, 2017

test windows_release_vs-integration_prtest please

These still fail once in a while in our branch. Likely fixed in master.

@VSadov
Copy link
Member Author

VSadov commented Aug 4, 2017

@dotnet/roslyn-compiler - please review

@jaredpar
Copy link
Member

jaredpar commented Aug 4, 2017

@tannergooding

so the default will be faster unverifiable code, but there will be an option to enable the slower verifiable code, correct?

As @VSadov noted, the problem is that peverify is not evolving at the moment. The code we generate is still type safe and can be verified as such according to verification rules we've sketched out. Need a new tool to catch up with our code :)

@tannergooding
Copy link
Member

@jaredpar, so this is essentially a safety fallback for users who still rely on peverify (or other outdated verification tools)?

@@ -163,6 +163,8 @@ internal override CommonAnonymousTypeManager CommonAnonymousTypeManager
/// </summary>
internal bool FeatureStrictEnabled => Feature("strict") != null;

internal bool FeaturePEVerifyCompatEnabled => Feature("peverify-compat") != null;
Copy link
Member

@jcouv jcouv Aug 4, 2017

Choose a reason for hiding this comment

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

Please add xml doc as above. #Resolved

CompileAndVerify(comp, verify: false, expectedOutput: @"
3
42
2
Copy link
Member

@jcouv jcouv Aug 4, 2017

Choose a reason for hiding this comment

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

The output is different from above. That seems surprising. #WontFix

Copy link
Member

@sharwell sharwell Aug 4, 2017

Choose a reason for hiding this comment

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

❓ I understand printing 2 here, but why 3 when peverify-compat is off? #WontFix

Copy link
Member

@sharwell sharwell Aug 4, 2017

Choose a reason for hiding this comment

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

Oh, I get it now. Passes a references to f instead of evaluating it. #WontFix

Copy link
Member

@sharwell sharwell Aug 4, 2017

Choose a reason for hiding this comment

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

I'm also concerned about this case. Is there a way to describe the cases which have observable changes and exclude them from peverify-compat? #WontFix

Copy link
Member Author

@VSadov VSadov Aug 4, 2017

Choose a reason for hiding this comment

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

The output is different because the flag currently deoptimizes overal treatment of readonly fields as lvalues in readonly context. Thus it affects scenarios where removing aliasing is observable. Generally those are scenarios involving readonly ref

This makes me think that perhaps we should not deoptimize those.
It could be hard, however, to distinguish situations where new features are involved since that could be very indirect.
#WontFix

Copy link
Member Author

@VSadov VSadov Aug 4, 2017

Choose a reason for hiding this comment

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

Basically, in the simplest case, - if you pass a readonly field to an in parameter do you want:
1 - never pass it by reference (defeats the purpose of the in, definitely no )
2 - always pass it by reference (triggers peverify complains)
3 - change the behavior based on the compat flag (some contorted code may see the difference)

We have #3 right now.
#WontFix

@jaredpar
Copy link
Member

jaredpar commented Aug 4, 2017

@tannergooding

so this is essentially a safety fallback for users who still rely on peverify (or other outdated verification tools)?

I wouldn't use the word safety here because of the nature of the problem. Nothing is unsafe here, peverify is just not keeping up with the language.

I prefer thinking of it as a release valve for customers who are impacted by this change. Our expectation is that this customer doesn't exist but given this is going into a point release of the language want to have a backup plan.

#WontFix

@@ -137,6 +137,11 @@ private bool IsDebugPlus()
return _module.Compilation.Options.DebugPlusMode;
}

private bool IsPEVerifyCompatible()
Copy link
Member

@jaredpar jaredpar Aug 4, 2017

Choose a reason for hiding this comment

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

Name sits wrong with me. Think it would read better as matching the option name. Say: EnablePEVerifyCompat #Resolved

Copy link
Member Author

Choose a reason for hiding this comment

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

I do not have much preferences here.


In reply to: 131440368 [](ancestors = 131440368)

IL_003c: ldflda ""MyManagedStruct.Nested.Nested1 MyManagedStruct.Nested.n""
IL_0032: ldfld ""MyManagedStruct cls1.y""
IL_0037: ldfld ""MyManagedStruct.Nested MyManagedStruct.n""
IL_003c: ldfld ""MyManagedStruct.Nested.Nested1 MyManagedStruct.Nested.n""
IL_0041: ldfld ""int MyManagedStruct.Nested.Nested1.num""
IL_0046: call ""void System.Console.WriteLine(int)""
IL_004b: ret
}
");
}

Copy link
Member

@jaredpar jaredpar Aug 4, 2017

Choose a reason for hiding this comment

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

Let's add a test trait for PEVerifyCompat mode and mark the new tests as such. That will make it easy to remove the feature later on if we make that decision. #Resolved

Copy link
Member Author

Choose a reason for hiding this comment

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

compiling with WithPEVerifyCompatFeature is a fairly robust indication, but can add a trait too.


In reply to: 131440583 [](ancestors = 131440583)

@jcouv
Copy link
Member

jcouv commented Aug 4, 2017

From discussion with Vlad, it is surprising that an "optimization" or "de-optimization" would have observable effects. The new language semantics need to be documented.

From our discussion, it sounds like the flag should have no observable effect on old code. So I'd recommend one of two approaches:

  1. the feature flag should only remove the optimization on "old" code, where it is not observable. "New" code is not PE-verifiable anyways.
  2. the feature flag should produce a warning if used in compilation with "new" code (7.2, ref readonly, or anything that makes the optimization observable)

From further discussion, this observable change is an acceptable break (very corner case). #Resolved

@VSadov
Copy link
Member Author

VSadov commented Aug 4, 2017

Discussed further. - The goal of the flag is a last resort way to suppress peverify errors. It would not be generally used or recommended as a long term solution.
We are ok with suboptimal codegen and deviation from spec in unusual corner cases.


In reply to: 320316384 [](ancestors = 320316384)

@VSadov
Copy link
Member Author

VSadov commented Aug 4, 2017

any more suggestion on this one?

@VSadov
Copy link
Member Author

VSadov commented Aug 7, 2017

@dotnet/roslyn-compiler - PING

@sharwell
Copy link
Member

sharwell commented Aug 7, 2017

@VSadov When this flag is documented, consider adding a recommendation similar to the following:

⚠️ In certain edge cases, this flag will produce code which deviates from the C# language specification due to limitations in the PEVerify implementation. For application consistency, users are encouraged to use the output from this feature only for passing to PEVerify, and using a second build where this feature is not enabled at execution time.

Copy link
Member

@jcouv jcouv left a comment

Choose a reason for hiding this comment

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

LGTM

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.

6 participants