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

Add internal instrumentation API for switch expression arm's expression #43430

Merged
11 commits merged into from
Apr 27, 2020

Conversation

gafter
Copy link
Member

@gafter gafter commented Apr 16, 2020

Fixes #42810

@gafter
Copy link
Member Author

gafter commented Apr 16, 2020

@dotnet/roslyn-compiler @dotnet/roslyn-analysis Could you please have a look at this?

// Should go through this._localRewriter._instrumenter; see https://github.com/dotnet/roslyn/issues/42810
loweredValue = new BoundSequencePointExpression(arm.Value.Syntax, loweredValue, loweredValue.Type);
}
loweredValue = this._localRewriter._instrumenter.InstrumentSwitchExpressionArmExpression(arm.Value, loweredValue, _factory);
Copy link
Contributor

@AlekseyTs AlekseyTs Apr 19, 2020

Choose a reason for hiding this comment

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

loweredValue = this._localRewriter._instrumenter.InstrumentSwitchExpressionArmExpression(arm.Value, loweredValue, _factory); [](start = 24, length = 124)

It is not clear why instrumentation would be linked to generation of sequence points. #Closed

Copy link
Member Author

@gafter gafter Apr 20, 2020

Choose a reason for hiding this comment

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

If you prefer I will rename GenerateSequencePoints to GenerateInstrumentation. #Resolved

@@ -92,10 +92,7 @@ private BoundExpression LowerSwitchExpression(BoundConvertedSwitchExpression nod
sectionBuilder.Add(_factory.Label(arm.Label));
var loweredValue = _localRewriter.VisitExpression(arm.Value);
if (GenerateSequencePoints)
{
Copy link
Contributor

@AlekseyTs AlekseyTs Apr 19, 2020

Choose a reason for hiding this comment

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

{ [](start = 20, length = 1)

If we are going to keep the if at the end, consider keeping braces as well. #Closed

Copy link
Member Author

Choose a reason for hiding this comment

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

All single-line if statements in this source file are without braces. I prefer to maintain that consistency.


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

@AlekseyTs
Copy link
Contributor

AlekseyTs commented Apr 19, 2020

Done with review pass (iteration 1). I would expect to see some tests verifying that instrumentation is happening as expected even when no debug information is generated. #WontFix

@gafter
Copy link
Member Author

gafter commented Apr 20, 2020

As you can see from the implementation in Instrumenter.cs, we do not currently instrument any parts of a switch expression. See Instrumenter.InstrumentSwitchWhenClauseConditionalGotoBody and Instrumenter.InstrumentSwitchExpressionArmExpression. The purpose of this PR is to go through those hooks when producing instrumentation such as debugging output or instrumentation. Since we do not produce instrumentation, there is no observable change to the external behavior of the compiler due to this PR.


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

@gafter
Copy link
Member Author

gafter commented Apr 20, 2020

@AlekseyTs I think I've responded to all of your comments.

@agocke @RikkiGibson Could you please review this?

@@ -904,7 +904,7 @@ private void LowerWhenClause(BoundWhenDecisionDagNode whenClause)

// We hide the jump back into the decision dag, as it is not logically part of the when clause
BoundStatement jump = _factory.Goto(GetDagNodeLabel(whenFalse));
sectionBuilder.Add(GenerateSequencePoints ? _factory.HiddenSequencePoint(jump) : jump);
sectionBuilder.Add(GenerateInstrumentation ? _factory.HiddenSequencePoint(jump) : jump);
Copy link
Contributor

@AlekseyTs AlekseyTs Apr 21, 2020

Choose a reason for hiding this comment

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

GenerateInstrumentation [](start = 39, length = 23)

It is not clear why generation of hidden sequence points is conditioned on instrumentation #Resolved

Copy link
Member Author

@gafter gafter Apr 21, 2020

Choose a reason for hiding this comment

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

Because we produce sequence points whenever we use the instrumentation API and only then. Hidden sequence points are needed here when we are producing sequence points. (When not producing a pdb, the hidden sequence points are dropped on the floor later along with the sequence points). It is only because this code is shared between contexts in which we are producing sequence points (e.g. the switch statement) and those in which are are not (e.g. the is-pattern expression) that we need this conditional.


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

@@ -26,7 +26,7 @@ private sealed class SwitchStatementLocalRewriter : BaseSwitchLocalRewriter
/// </summary>
private readonly Dictionary<SyntaxNode, LabelSymbol> _sectionLabels = PooledDictionary<SyntaxNode, LabelSymbol>.GetInstance();

protected override bool GenerateSequencePoints => true;
protected override bool GenerateInstrumentation => true;
Copy link
Contributor

@AlekseyTs AlekseyTs Apr 21, 2020

Choose a reason for hiding this comment

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

true [](start = 63, length = 4)

Unconditional instrumentation feels suspicious #Closed

Copy link
Member Author

Choose a reason for hiding this comment

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

All statements are instrumented today. For example, this long appears (without any condition) in LocalRewriter.VisitBlock:

            BoundStatement? prologue = _instrumenter.CreateBlockPrologue(node, out synthesizedLocal);

Normally we simply call the instrumentation API when lowering a statement. Since this overrides a method in code that is shared between processing expressions (e.g. the is-pattern expression) and statmements (e.g. the switch statement) we use this to communicate which kind of context we are in.


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

Copy link
Contributor

Choose a reason for hiding this comment

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

Normally we instrument conditionally, based on LocalRewriter.Instrument value. Even the LocalRewriter.VisitBlock that you use as an example bypasses instrumentation when LocalRewriter.Instrument is false (see an if statement 5 lines above). I expect at least that value to be always taken into account.


In reply to: 412452424 [](ancestors = 412452424,412362045)

@AlekseyTs
Copy link
Contributor

AlekseyTs commented Apr 21, 2020

The API got hooked into the product, therefore we should find a way to test it. It is quite possible that the easiest way to do that is to implement instrumentation in DynamicAnalysisInjector. Alternatively we can unhook the API, keep this as just an introduction of the API. And hook it into the product once we are comfortable with its shape and ready to test its usage proper.


In reply to: 616714458 [](ancestors = 616714458,616222134)

@AlekseyTs
Copy link
Contributor

Done with review pass (iteration 3)

@gafter
Copy link
Member Author

gafter commented Apr 21, 2020

It is tested. We go through this API to produce the sequence points, and there are many existing tests that demonstrate the presence of the sequence points produced through this API.


In reply to: 617316315 [](ancestors = 617316315,616714458,616222134)

@AlekseyTs
Copy link
Contributor

AlekseyTs commented Apr 21, 2020

It is tested. We go through this API to produce the sequence points, and there are many existing tests that demonstrate the presence of the sequence points produced through this API.

The change adds zero tests. I have doubts about conditions under which the instrumentation is invoked. The only way to eliminate them is through tests. I don't think we can rely on existing tests around debug information (sequence points) because I am specifically concerned about scenarios where we instrument, but do not generate debug information and vise versa.


In reply to: 617380907 [](ancestors = 617380907,617316315,616714458,616222134)

@gafter
Copy link
Member Author

gafter commented Apr 21, 2020

This is exactly the same as InstrumentSwitchStatementExpression, InstrumentCatchClauseFilter and others which you added but without the same kind of tests that you now seem to think are required. How did you eliminate your doubts then?


In reply to: 617388877 [](ancestors = 617388877,617380907,617316315,616714458,616222134)

@AlekseyTs
Copy link
Contributor

AlekseyTs commented Apr 21, 2020

This is exactly the same as InstrumentSwitchStatementExpression, InstrumentCatchClauseFilter and others which you added but without the same kind of tests that you now seem to think are required. How did you eliminate your doubts then?

I assume the scenarios are tested under umbrella of dynamic analysis tests. I also had more context at the time, given that the feature was under active development and I was working on it. Right now, I am reviewing the code, the code that is either new, or significantly modified since then. The code that appears to use some different logic around invoking instrumentation. All I have to go from - is my intuition, which might or might not be wrong. If you are so against adding tests, I suggest a compromise - let's remove usage of the new API from the product and start using it when we can easily test its actual effect under different conditions, or add a PROTOTYPE comment in the right place to catch up on testing later.


In reply to: 617397889 [](ancestors = 617397889,617388877,617380907,617316315,616714458,616222134)

@gafter
Copy link
Member Author

gafter commented Apr 21, 2020

No, the new API is used to produce debugging support for these contexts, just like for InstrumentSwitchStatementExpression, InstrumentCatchClauseFilter and others. There are many tests that confirm that the debugging information is present where the new API is called. Adding a PROTOTYPE comment will not facilitate merging into master this week. I am confident that the testing of the use of the APIs is more than sufficient.


In reply to: 617406776 [](ancestors = 617406776,617397889,617388877,617380907,617316315,616714458,616222134)

@AlekseyTs
Copy link
Contributor

No, the new API is used to produce debugging support for these contexts, just like for InstrumentSwitchStatementExpression, InstrumentCatchClauseFilter and others. There are many tests that confirm that the debugging information is present where the new API is called. Adding a PROTOTYPE comment will not facilitate merging into master this week. I am confident that the testing of the use of the APIs is more than sufficient.

Since using or not using the API makes no difference. If we unhook that one call, there would be no observable behavior change and we can merge to master.


In reply to: 617409044 [](ancestors = 617409044,617406776,617397889,617388877,617380907,617316315,616714458,616222134)

@AlekseyTs
Copy link
Contributor

To be honest, I don't understand why you don't want to implement dynamic analysis for this case, we should have examples how to instrument expressions and I don't think this one is special in any way.


In reply to: 617411518 [](ancestors = 617411518,617409044,617406776,617397889,617388877,617380907,617316315,616714458,616222134)

… statements or in expression lambdas.

Though neither of these conditions is possible today.
@gafter
Copy link
Member Author

gafter commented Apr 21, 2020

I do not intend to design the experience of instrumentation for expressions. I intend to work with the team responsible for that to help them design the experience they intend.

Removing the invocation of the new API would indeed break a bunch of tests. That's how we know it works.


In reply to: 617412554 [](ancestors = 617412554,617411518,617409044,617406776,617397889,617388877,617380907,617316315,616714458,616222134)

@AlekseyTs
Copy link
Contributor

Removing the invocation of the new API would indeed break a bunch of tests. That's how we know it works.

I guess I wasn't clear enough. I meant to restore loweredValue = new BoundSequencePointExpression(arm.Value.Syntax, loweredValue, loweredValue.Type); back and remove the loweredValue = this._localRewriter._instrumenter.InstrumentSwitchExpressionArmExpression(arm.Value, loweredValue, _factory); in the LowerSwitchExpression method.That change is completely unobservable.


In reply to: 617422758 [](ancestors = 617422758,617412554,617411518,617409044,617406776,617397889,617388877,617380907,617316315,616714458,616222134)

@AlekseyTs
Copy link
Contributor

AlekseyTs commented Apr 21, 2020

I intend to work with the team responsible for that to help them design the experience they intend.

What is the plan here? At what point that work is going to start? Is it really necessary to merge the API into master before the shape of the API is finalized and, at least, proven to work through implementing dynamic analysis (at least as a prototype)? #Resolved

@gafter
Copy link
Member Author

gafter commented Apr 21, 2020

We only produce a BoundSequencePointExpression through the instrumentation APIs.


In reply to: 617429142 [](ancestors = 617429142,617422758,617412554,617411518,617409044,617406776,617397889,617388877,617380907,617316315,616714458,616222134)

@gafter
Copy link
Member Author

gafter commented Apr 21, 2020

Since we use the instrumentation API to produce all sequence points for breakpoint locations, and since you commented on a previous PR that it was necessary to do so, yes, it is necessary. There is an issue (#43544) tracking the dynamic instrumentation work, and I do not yet have insight into that team's plans or designs for when or how they intend to proceed. I am fine with this API changing in the future in the unlikely event it is found to need changes for dynamic analysis; this shape of the API is sufficient for producing debugging breakpoints.


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

@AlekseyTs
Copy link
Contributor

AlekseyTs commented Apr 21, 2020

There is an issue (#43544) tracking the dynamic instrumentation work

Thank you for opening the issue to track completion of the work. This address my final concerns regarding this PR. #Resolved

Copy link
Contributor

@AlekseyTs AlekseyTs left a comment

Choose a reason for hiding this comment

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

LGTM (iteration 5)

@gafter
Copy link
Member Author

gafter commented Apr 24, 2020

Reviewers: I have added an iteration to fix an order-of-initialization bug. Please let me know if you have any comments on that.

@AlekseyTs
Copy link
Contributor

Reviewers: I have added an iteration to fix an order-of-initialization bug. Please let me know if you have any comments on that.

I do not see anything obviously wrong in the 10th commit

Copy link

@ghost ghost left a comment

Choose a reason for hiding this comment

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

Auto-approval

@gafter gafter closed this Apr 27, 2020
@gafter gafter reopened this Apr 27, 2020
@ghost ghost merged commit 26d509b into dotnet:features/patterns3 Apr 27, 2020
This pull request was closed.
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.

3 participants