-
Notifications
You must be signed in to change notification settings - Fork 4k
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
Conversation
@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); |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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) | |||
{ |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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)
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 |
As you can see from the implementation in In reply to: 616222134 [](ancestors = 616222134) |
@AlekseyTs I think I've responded to all of your comments. @agocke @RikkiGibson Could you please review this? |
…into patterns3-42810
@@ -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); |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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; |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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)
There was a problem hiding this comment.
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)
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) |
Done with review pass (iteration 3) |
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) |
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) |
This is exactly the same as In reply to: 617388877 [](ancestors = 617388877,617380907,617316315,616714458,616222134) |
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) |
No, the new API is used to produce debugging support for these contexts, just like for In reply to: 617406776 [](ancestors = 617406776,617397889,617388877,617380907,617316315,616714458,616222134) |
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) |
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.
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) |
I guess I wasn't clear enough. I meant to restore In reply to: 617422758 [](ancestors = 617422758,617412554,617411518,617409044,617406776,617397889,617388877,617380907,617316315,616714458,616222134) |
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 |
We only produce a In reply to: 617429142 [](ancestors = 617429142,617422758,617412554,617411518,617409044,617406776,617397889,617388877,617380907,617316315,616714458,616222134) |
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) |
Thank you for opening the issue to track completion of the work. This address my final concerns regarding this PR. #Resolved |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM (iteration 5)
…into patterns3-42810
…into patterns3-42810
…to patterns3-42810
…into patterns3-42810
(It used to depend on calling a virtual property `GenerateInstrumentation` implemented in a subtype)
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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Auto-approval
…into patterns3-42810
Fixes #42810