/// <summary> /// Rewrite an async method into a state machine type. /// </summary> internal static BoundStatement Rewrite( BoundStatement body, MethodSymbol method, int methodOrdinal, VariableSlotAllocator slotAllocatorOpt, TypeCompilationState compilationState, DiagnosticBag diagnostics, out AsyncStateMachine stateMachineType) { if (!method.IsAsync) { stateMachineType = null; return body; } // The CLR doesn't support adding fields to structs, so in order to enable EnC in an async method we need to generate a class. var typeKind = compilationState.Compilation.Options.EnableEditAndContinue ? TypeKind.Class : TypeKind.Struct; var bodyWithAwaitLifted = AwaitExpressionSpiller.Rewrite(body, method, compilationState, diagnostics); stateMachineType = new AsyncStateMachine(slotAllocatorOpt, compilationState, method, methodOrdinal, typeKind); compilationState.ModuleBuilderOpt.CompilationState.SetStateMachineType(method, stateMachineType); var rewriter = new AsyncRewriter(bodyWithAwaitLifted, method, methodOrdinal, stateMachineType, slotAllocatorOpt, compilationState, diagnostics); if (!rewriter.VerifyPresenceOfRequiredAPIs()) { return body; } return rewriter.Rewrite(); }
internal static BoundStatement AddSequencePoint(BlockSyntax blockSyntax, BoundStatement rewrittenStatement, bool isPrimaryCtor) { TextSpan span; if (isPrimaryCtor) { // For a primary constructor block: ... [|{|] ... } return new BoundSequencePointWithSpan(blockSyntax, rewrittenStatement, blockSyntax.OpenBraceToken.Span); } var parent = blockSyntax.Parent as ConstructorDeclarationSyntax; if (parent != null) { span = CreateSpanForConstructorDeclaration(parent); } else { // This inserts a sequence points to any prologue code for method declarations. var start = blockSyntax.Parent.SpanStart; var end = blockSyntax.OpenBraceToken.GetPreviousToken().Span.End; span = TextSpan.FromBounds(start, end); } return new BoundSequencePointWithSpan(blockSyntax, rewrittenStatement, span); }
/// <summary> /// Rewrite an async method into a state machine class. /// </summary> /// <param name="body">The original body of the method</param> /// <param name="method">The method's identity</param> /// <param name="compilationState">The collection of generated methods that result from this transformation and which must be emitted</param> /// <param name="diagnostics">Diagnostic bag for diagnostics.</param> /// <param name="generateDebugInfo"></param> /// <param name="stateMachineType"></param> internal static BoundStatement Rewrite( BoundStatement body, MethodSymbol method, TypeCompilationState compilationState, DiagnosticBag diagnostics, bool generateDebugInfo, out AsyncStateMachine stateMachineType) { if (!method.IsAsync) { stateMachineType = null; return body; } // The CLR doesn't support adding fields to structs, so in order to enable EnC in an async method we need to generate a class. var typeKind = compilationState.Compilation.Options.EnableEditAndContinue ? TypeKind.Class : TypeKind.Struct; var bodyWithAwaitLifted = AwaitLiftingRewriter.Rewrite(body, method, compilationState, diagnostics); stateMachineType = new AsyncStateMachine(method, typeKind); compilationState.ModuleBuilderOpt.CompilationState.SetStateMachineType(method, stateMachineType); var rewriter = new AsyncRewriter(bodyWithAwaitLifted, method, stateMachineType, compilationState, diagnostics, generateDebugInfo); if (!rewriter.constructedSuccessfully) { return body; } return rewriter.Rewrite(); }
/// <summary> /// Rewrite an iterator method into a state machine class. /// </summary> /// <param name="body">The original body of the method</param> /// <param name="method">The method's identity</param> /// <param name="compilationState">The collection of generated methods that result from this transformation and which must be emitted</param> /// <param name="diagnostics">Diagnostic bag for diagnostics.</param> /// <param name="generateDebugInfo"></param> internal static BoundStatement Rewrite( BoundStatement body, MethodSymbol method, TypeCompilationState compilationState, DiagnosticBag diagnostics, bool generateDebugInfo) { TypeSymbol elementType = method.IteratorElementType; if ((object)elementType == null) { return body; } // Figure out what kind of iterator we are generating. bool isEnumerable; switch (method.ReturnType.OriginalDefinition.SpecialType) { case SpecialType.System_Collections_IEnumerable: case SpecialType.System_Collections_Generic_IEnumerable_T: isEnumerable = true; break; case SpecialType.System_Collections_IEnumerator: case SpecialType.System_Collections_Generic_IEnumerator_T: isEnumerable = false; break; default: throw ExceptionUtilities.UnexpectedValue(method.ReturnType.OriginalDefinition.SpecialType); } var iteratorClass = new IteratorStateMachine(method, isEnumerable, elementType, compilationState); return new IteratorRewriter(body, method, isEnumerable, iteratorClass, compilationState, diagnostics, generateDebugInfo).Rewrite(); }
// insert the implicit "return" statement at the end of the method body // Normally, we wouldn't bother attaching syntax trees to compiler-generated nodes, but these // ones are going to have sequence points. internal static BoundBlock AppendImplicitReturn(BoundStatement node, MethodSymbol method = null, CSharpSyntaxNode syntax = null) { if (syntax == null) { syntax = node.Syntax; } BoundStatement ret = (object)method != null && (object)method.IteratorElementType != null ? BoundYieldBreakStatement.Synthesized(syntax) as BoundStatement : BoundReturnStatement.Synthesized(syntax, null); if (syntax.Kind == SyntaxKind.Block) { var blockSyntax = (BlockSyntax)syntax; ret = new BoundSequencePointWithSpan( blockSyntax, ret, blockSyntax.CloseBraceToken.Span) { WasCompilerGenerated = true }; } switch (node.Kind) { case BoundKind.Block: var block = (BoundBlock)node; return block.Update(block.LocalsOpt, block.Statements.Add(ret)); default: return new BoundBlock(syntax, ImmutableArray<LocalSymbol>.Empty, ImmutableArray.Create(ret, node)); } }
protected StateMachineRewriter( BoundStatement body, MethodSymbol method, SynthesizedContainer stateMachineType, VariableSlotAllocator slotAllocatorOpt, TypeCompilationState compilationState, DiagnosticBag diagnostics) { Debug.Assert(body != null); Debug.Assert(method != null); Debug.Assert(stateMachineType != null); Debug.Assert(compilationState != null); Debug.Assert(diagnostics != null); this.body = body; this.method = method; this.stateMachineType = stateMachineType; this.slotAllocatorOpt = slotAllocatorOpt; this.synthesizedLocalOrdinals = new SynthesizedLocalOrdinalsDispenser(); this.diagnostics = diagnostics; this.F = new SyntheticBoundNodeFactory(method, body.Syntax, compilationState, diagnostics); Debug.Assert(F.CurrentType == method.ContainingType); Debug.Assert(F.Syntax == body.Syntax); }
/// <summary> /// Is there any code to execute in the given statement that could have side-effects, /// such as throwing an exception? This implementation is conservative, in the sense /// that it may return true when the statement actually may have no side effects. /// </summary> private static bool HasSideEffects(BoundStatement statement) { if (statement == null) return false; switch (statement.Kind) { case BoundKind.NoOpStatement: return true; case BoundKind.Block: { var block = (BoundBlock)statement; foreach (var stmt in block.Statements) { if (HasSideEffects(stmt)) return true; } return false; } case BoundKind.SequencePoint: { var sequence = (BoundSequencePoint)statement; return HasSideEffects(sequence.StatementOpt); } case BoundKind.SequencePointWithSpan: { var sequence = (BoundSequencePointWithSpan)statement; return HasSideEffects(sequence.StatementOpt); } default: return true; } }
internal static BoundStatement AddSequencePoint(UsingStatementSyntax usingSyntax, BoundStatement rewrittenStatement) { int start = usingSyntax.Span.Start; int end = usingSyntax.CloseParenToken.Span.End; TextSpan span = TextSpan.FromBounds(start, end); return new BoundSequencePointWithSpan(usingSyntax, rewrittenStatement, span); }
public static DynamicAnalysisInjector TryCreate(MethodSymbol method, BoundStatement methodBody, SyntheticBoundNodeFactory methodBodyFactory, DiagnosticBag diagnostics, DebugDocumentProvider debugDocumentProvider, Instrumenter previous) { // Do not instrument implicitly-declared methods, except for constructors. // Instrument implicit constructors in order to instrument member initializers. if (method.IsImplicitlyDeclared && !method.IsImplicitConstructor) { return null; } // Do not instrument methods marked with or in scope of ExcludeFromCodeCoverageAttribute. if (IsExcludedFromCodeCoverage(method)) { return null; } MethodSymbol createPayload = GetCreatePayload(methodBodyFactory.Compilation, methodBody.Syntax, diagnostics); // Do not instrument any methods if CreatePayload is not present. if ((object)createPayload == null) { return null; } // Do not instrument CreatePayload if it is part of the current compilation (which occurs only during testing). // CreatePayload will fail at run time with an infinite recursion if it is instrumented. if (method.Equals(createPayload)) { return null; } return new DynamicAnalysisInjector(method, methodBody, methodBodyFactory, createPayload, diagnostics, debugDocumentProvider, previous); }
private BoundStatement RewriteWhileStatement( BoundLoopStatement loop, BoundExpression rewrittenCondition, BoundStatement rewrittenBody, GeneratedLabelSymbol breakLabel, GeneratedLabelSymbol continueLabel, bool hasErrors) { Debug.Assert(loop.Kind == BoundKind.WhileStatement || loop.Kind == BoundKind.ForEachStatement); // while (condition) // body; // // becomes // // goto continue; // start: // { // body // continue: // GotoIfTrue condition start; // } // break: SyntaxNode syntax = loop.Syntax; var startLabel = new GeneratedLabelSymbol("start"); BoundStatement ifConditionGotoStart = new BoundConditionalGoto(rewrittenCondition.Syntax, rewrittenCondition, true, startLabel); BoundStatement gotoContinue = new BoundGotoStatement(syntax, continueLabel); if (this.Instrument && !loop.WasCompilerGenerated) { switch (loop.Kind) { case BoundKind.WhileStatement: ifConditionGotoStart = _instrumenter.InstrumentWhileStatementConditionalGotoStartOrBreak((BoundWhileStatement)loop, ifConditionGotoStart); break; case BoundKind.ForEachStatement: ifConditionGotoStart = _instrumenter.InstrumentForEachStatementConditionalGotoStart((BoundForEachStatement)loop, ifConditionGotoStart); break; default: throw ExceptionUtilities.UnexpectedValue(loop.Kind); } // mark the initial jump as hidden. We do it to tell that this is not a part of previous statement. This // jump may be a target of another jump (for example if loops are nested) and that would give the // impression that the previous statement is being re-executed. gotoContinue = new BoundSequencePoint(null, gotoContinue); } return BoundStatementList.Synthesized(syntax, hasErrors, gotoContinue, new BoundLabelStatement(syntax, startLabel), rewrittenBody, new BoundLabelStatement(syntax, continueLabel), ifConditionGotoStart, new BoundLabelStatement(syntax, breakLabel)); }
private static BoundStatement RewriteIfStatement( CSharpSyntaxNode syntax, ImmutableArray<LocalSymbol> locals, BoundExpression rewrittenCondition, BoundStatement rewrittenConsequence, BoundStatement rewrittenAlternativeOpt, bool hasErrors) { var afterif = new GeneratedLabelSymbol("afterif"); var builder = ArrayBuilder<BoundStatement>.GetInstance(); if (rewrittenAlternativeOpt == null) { // if (condition) // consequence; // // becomes // // GotoIfFalse condition afterif; // consequence; // afterif: builder.Add(new BoundConditionalGoto(rewrittenCondition.Syntax, rewrittenCondition, false, afterif)); builder.Add(rewrittenConsequence); } else { // if (condition) // consequence; // else // alternative // // becomes // // GotoIfFalse condition alt; // consequence // goto afterif; // alt: // alternative; // afterif: var alt = new GeneratedLabelSymbol("alternative"); builder.Add(new BoundConditionalGoto(rewrittenCondition.Syntax, rewrittenCondition, false, alt)); builder.Add(rewrittenConsequence); builder.Add(new BoundGotoStatement(syntax, afterif)); builder.Add(new BoundLabelStatement(syntax, alt)); builder.Add(rewrittenAlternativeOpt); } builder.Add(new BoundLabelStatement(syntax, afterif)); if (!locals.IsDefaultOrEmpty) { return new BoundBlock(syntax, locals, builder.ToImmutableAndFree(), hasErrors); } return new BoundStatementList(syntax, builder.ToImmutableAndFree(), hasErrors); }
internal static BoundStatement AddSequencePoint(VariableDeclaratorSyntax declaratorSyntax, BoundStatement rewrittenStatement) { SyntaxNode node; TextSpan? part; GetBreakpointSpan(declaratorSyntax, out node, out part); var result = BoundSequencePoint.Create(declaratorSyntax, part, rewrittenStatement); result.WasCompilerGenerated = rewrittenStatement.WasCompilerGenerated; return result; }
internal MethodWithBody(MethodSymbol method, BoundStatement body, ImportChain importChainOpt) { Debug.Assert(method != null); Debug.Assert(body != null); this.Method = method; this.Body = body; this.ImportChainOpt = importChainOpt; }
private static BoundStatement RewriteIfStatement( CSharpSyntaxNode syntax, BoundExpression rewrittenCondition, BoundStatement rewrittenConsequence, BoundStatement rewrittenAlternativeOpt, bool hasErrors) { return RewriteIfStatement(syntax, ImmutableArray<LocalSymbol>.Empty, rewrittenCondition, rewrittenConsequence, rewrittenAlternativeOpt, hasErrors); }
public override BoundNode VisitFixedStatement(BoundFixedStatement node) { int numFixedLocals = node.Locals.Length; var localBuilder = ArrayBuilder<LocalSymbol>.GetInstance(numFixedLocals); localBuilder.AddRange(node.Locals); var statementBuilder = ArrayBuilder<BoundStatement>.GetInstance(numFixedLocals + 1 + 1); //+1 for body, +1 for hidden seq point var cleanup = new BoundStatement[numFixedLocals]; ImmutableArray<BoundLocalDeclaration> localDecls = node.Declarations.LocalDeclarations; Debug.Assert(localDecls.Length == numFixedLocals); for (int i = 0; i < numFixedLocals; i++) { BoundLocalDeclaration localDecl = localDecls[i]; LocalSymbol temp; LocalSymbol localToClear; statementBuilder.Add(InitializeFixedStatementLocal(localDecl, factory, out temp, out localToClear)); if (!ReferenceEquals(temp, null)) { localBuilder.Add(temp); } // NOTE: Dev10 nulls out the locals in declaration order (as opposed to "popping" them in reverse order). cleanup[i] = factory.Assignment(factory.Local(localToClear), factory.Null(localToClear.Type)); } BoundStatement rewrittenBody = VisitStatement(node.Body); statementBuilder.Add(rewrittenBody); statementBuilder.Add(factory.HiddenSequencePoint()); Debug.Assert(statementBuilder.Count == numFixedLocals + 1 + 1); // In principle, the cleanup code (i.e. nulling out the pinned variables) is always // in a finally block. However, we can optimize finally away (keeping the cleanup // code) in cases where both of the following are true: // 1) there are no branches out of the fixed statement; and // 2) the fixed statement is not in a try block (syntactic or synthesized). if (IsInTryBlock(node) || HasGotoOut(rewrittenBody)) { return factory.Block( localBuilder.ToImmutableAndFree(), new BoundTryStatement( factory.Syntax, factory.Block(statementBuilder.ToImmutableAndFree()), ImmutableArray<BoundCatchBlock>.Empty, factory.Block(cleanup))); } else { statementBuilder.AddRange(cleanup); return factory.Block(localBuilder.ToImmutableAndFree(), statementBuilder.ToImmutableAndFree()); } }
protected override void ResolveBranch(PendingBranch pending, LabelSymbol label, BoundStatement target, ref bool labelStateChanged) { // branches into a region are considered entry points if (IsInside && pending.Branch != null && !RegionContains(pending.Branch.Syntax.Span)) { pending.State = pending.State.Reachable ? ReachableState() : UnreachableState(); } base.ResolveBranch(pending, label, target, ref labelStateChanged); }
internal static BoundStatement AddSequencePoint(PropertyDeclarationSyntax declarationSyntax, BoundStatement rewrittenStatement) { Debug.Assert(declarationSyntax.Initializer != null); int start = declarationSyntax.Initializer.Value.SpanStart; int end = declarationSyntax.Initializer.Span.End; TextSpan part = TextSpan.FromBounds(start, end); var result = BoundSequencePoint.Create(declarationSyntax, part, rewrittenStatement); result.WasCompilerGenerated = rewrittenStatement.WasCompilerGenerated; return result; }
public static BoundStatement Create(CSharpSyntaxNode syntax, TextSpan? part, BoundStatement statement, bool hasErrors = false) { if (part.HasValue) { return new BoundSequencePointWithSpan(syntax, statement, part.Value, hasErrors); } else { return new BoundSequencePoint(syntax, statement, hasErrors); } }
private BoundStatement AddLocalDeclarationSequencePointIfNecessary(CSharpSyntaxNode syntax, LocalSymbol localSymbol, BoundStatement rewrittenLocalDeclaration, bool wasCompilerGenerated = false) { // Add sequence points, if necessary. if (this.GenerateDebugInfo && !wasCompilerGenerated && !localSymbol.IsConst && syntax.Kind() == SyntaxKind.VariableDeclarator) { Debug.Assert(syntax.SyntaxTree != null); rewrittenLocalDeclaration = AddSequencePoint((VariableDeclaratorSyntax)syntax, rewrittenLocalDeclaration); } return rewrittenLocalDeclaration; }
protected override void NoteBranch( PendingBranch pending, BoundNode gotoStmt, BoundStatement targetStmt) { targetStmt.AssertIsLabeledStatement(); if (!gotoStmt.WasCompilerGenerated && !targetStmt.WasCompilerGenerated && !RegionContains(gotoStmt.Syntax.Span) && RegionContains(targetStmt.Syntax.Span)) { pending.State = ResetState(pending.State); } base.NoteBranch(pending, gotoStmt, targetStmt); }
private BoundStatement InstrumentLocalDeclarationIfNecessary(BoundLocalDeclaration originalOpt, LocalSymbol localSymbol, BoundStatement rewrittenLocalDeclaration) { // Add sequence points, if necessary. if (this.Instrument && originalOpt?.WasCompilerGenerated == false && !localSymbol.IsConst && (originalOpt.Syntax.Kind() == SyntaxKind.VariableDeclarator || (originalOpt.Syntax.Kind() == SyntaxKind.LocalDeclarationStatement && ((LocalDeclarationStatementSyntax)originalOpt.Syntax).Declaration.Variables.Count == 1))) { rewrittenLocalDeclaration = _instrumenter.InstrumentLocalInitialization(originalOpt, rewrittenLocalDeclaration); } return rewrittenLocalDeclaration; }
private IteratorRewriter( BoundStatement body, MethodSymbol method, bool isEnumerable, IteratorStateMachine iteratorClass, TypeCompilationState compilationState, DiagnosticBag diagnostics) : base(body, method, iteratorClass, compilationState, diagnostics) { // the element type may contain method type parameters, which are now alpha-renamed into type parameters of the generated class this.elementType = iteratorClass.ElementType; this.isEnumerable = isEnumerable; }
private AsyncRewriter( BoundStatement body, MethodSymbol method, int methodOrdinal, AsyncStateMachine stateMachineType, VariableSlotAllocator slotAllocatorOpt, TypeCompilationState compilationState, DiagnosticBag diagnostics) : base(body, method, stateMachineType, slotAllocatorOpt, compilationState, diagnostics) { _constructedSuccessfully = AsyncMethodBuilderMemberCollection.TryCreate(F, method, this.stateMachineType.TypeMap, out _asyncMethodBuilderMemberCollection); _methodOrdinal = methodOrdinal; _ignoreAccessibility = compilationState.ModuleBuilderOpt.IgnoreAccessibility; }
internal static ImmutableArray<BoundStatement> ConstructScriptConstructorBody( BoundStatement loweredBody, MethodSymbol constructor, SynthesizedSubmissionFields previousSubmissionFields, CSharpCompilation compilation) { // Script field initializers have to be emitted after the call to the base constructor because they can refer to "this" instance. // // Unlike regular field initializers, initializers of global script variables can access "this" instance. // If the base class had a constructor that initializes its state a global variable would access partially initialized object. // For this reason Script class must always derive directly from a class that has no state (System.Object). CSharpSyntaxNode syntax = loweredBody.Syntax; // base constructor call: Debug.Assert((object)constructor.ContainingType.BaseTypeNoUseSiteDiagnostics == null || constructor.ContainingType.BaseTypeNoUseSiteDiagnostics.SpecialType == SpecialType.System_Object); var objectType = constructor.ContainingAssembly.GetSpecialType(SpecialType.System_Object); BoundExpression receiver = new BoundThisReference(syntax, constructor.ContainingType) { WasCompilerGenerated = true }; BoundStatement baseConstructorCall = new BoundExpressionStatement(syntax, new BoundCall(syntax, receiverOpt: receiver, method: objectType.InstanceConstructors[0], arguments: ImmutableArray<BoundExpression>.Empty, argumentNamesOpt: ImmutableArray<string>.Empty, argumentRefKindsOpt: ImmutableArray<RefKind>.Empty, isDelegateCall: false, expanded: false, invokedAsExtensionMethod: false, argsToParamsOpt: ImmutableArray<int>.Empty, resultKind: LookupResultKind.Viable, type: objectType) { WasCompilerGenerated = true }) { WasCompilerGenerated = true }; var statements = ArrayBuilder<BoundStatement>.GetInstance(); statements.Add(baseConstructorCall); if (constructor.IsSubmissionConstructor) { // submission initialization: MakeSubmissionInitialization(statements, syntax, constructor, previousSubmissionFields, compilation); } statements.Add(loweredBody); return statements.ToImmutableAndFree(); }
private static BoundStatement RewriteIfStatement( CSharpSyntaxNode syntax, BoundExpression rewrittenCondition, BoundStatement rewrittenConsequence, BoundStatement rewrittenAlternativeOpt, bool hasErrors) { var afterif = new GeneratedLabelSymbol("afterif"); // if (condition) // consequence; // // becomes // // GotoIfFalse condition afterif; // consequence; // afterif: if (rewrittenAlternativeOpt == null) { return BoundStatementList.Synthesized(syntax, new BoundConditionalGoto(rewrittenCondition.Syntax, rewrittenCondition, false, afterif), rewrittenConsequence, new BoundLabelStatement(syntax, afterif)); } // if (condition) // consequence; // else // alternative // // becomes // // GotoIfFalse condition alt; // consequence // goto afterif; // alt: // alternative; // afterif: var alt = new GeneratedLabelSymbol("alternative"); return BoundStatementList.Synthesized(syntax, hasErrors, new BoundConditionalGoto(rewrittenCondition.Syntax, rewrittenCondition, false, alt), rewrittenConsequence, new BoundGotoStatement(syntax, afterif), new BoundLabelStatement(syntax, alt), rewrittenAlternativeOpt, new BoundLabelStatement(syntax, afterif)); }
private IteratorRewriter( BoundStatement body, MethodSymbol method, bool isEnumerable, IteratorStateMachine stateMachineType, VariableSlotAllocator slotAllocatorOpt, TypeCompilationState compilationState, DiagnosticBag diagnostics) : base(body, method, stateMachineType, slotAllocatorOpt, compilationState, diagnostics) { // the element type may contain method type parameters, which are now alpha-renamed into type parameters of the generated class _elementType = stateMachineType.ElementType; _isEnumerable = isEnumerable; }
private BoundStatement RewriteWhileStatement( CSharpSyntaxNode syntax, BoundExpression rewrittenCondition, TextSpan conditionSequencePointSpan, BoundStatement rewrittenBody, GeneratedLabelSymbol breakLabel, GeneratedLabelSymbol continueLabel, bool hasErrors) { var startLabel = new GeneratedLabelSymbol("start"); BoundStatement ifConditionGotoStart = new BoundConditionalGoto(rewrittenCondition.Syntax, rewrittenCondition, true, startLabel); if (this.GenerateDebugInfo) { ifConditionGotoStart = new BoundSequencePointWithSpan(syntax, ifConditionGotoStart, conditionSequencePointSpan); } // while (condition) // body; // // becomes // // goto continue; // start: // { // body // continue: // GotoIfTrue condition start; // } // break: BoundStatement gotoContinue = new BoundGotoStatement(syntax, continueLabel); if (this.GenerateDebugInfo) { // mark the initial jump as hidden. We do it to tell that this is not a part of previous statement. This // jump may be a target of another jump (for example if loops are nested) and that would give the // impression that the previous statement is being re-executed. gotoContinue = new BoundSequencePoint(null, gotoContinue); } return BoundStatementList.Synthesized(syntax, hasErrors, gotoContinue, new BoundLabelStatement(syntax, startLabel), rewrittenBody, new BoundLabelStatement(syntax, continueLabel), ifConditionGotoStart, new BoundLabelStatement(syntax, breakLabel)); }
protected StateMachineRewriter( BoundStatement body, MethodSymbol method, SynthesizedContainer stateMachineClass, TypeCompilationState compilationState, DiagnosticBag diagnostics) { this.body = body; this.method = method; this.stateMachineClass = stateMachineClass; this.compilationState = compilationState; this.diagnostics = diagnostics; this.F = new SyntheticBoundNodeFactory(method, body.Syntax, compilationState, diagnostics); Debug.Assert(F.CurrentClass == method.ContainingType); Debug.Assert(F.Syntax == body.Syntax); }
private DynamicAnalysisInjector(MethodSymbol method, BoundStatement methodBody, SyntheticBoundNodeFactory methodBodyFactory, MethodSymbol createPayload, DiagnosticBag diagnostics, DebugDocumentProvider debugDocumentProvider, Instrumenter previous) : base(previous) { _createPayload = createPayload; _method = method; _methodBody = methodBody; _spansBuilder = ArrayBuilder<SourceSpan>.GetInstance(); TypeSymbol payloadElementType = methodBodyFactory.SpecialType(SpecialType.System_Boolean); _payloadType = ArrayTypeSymbol.CreateCSharpArray(methodBodyFactory.Compilation.Assembly, payloadElementType); _methodPayload = methodBodyFactory.SynthesizedLocal(_payloadType, kind: SynthesizedLocalKind.InstrumentationPayload, syntax: methodBody.Syntax); _diagnostics = diagnostics; _debugDocumentProvider = debugDocumentProvider; _methodHasExplicitBlock = MethodHasExplicitBlock(method); _methodBodyFactory = methodBodyFactory; // The first point indicates entry into the method and has the span of the method definition. _methodEntryInstrumentation = AddAnalysisPoint(MethodDeclarationIfAvailable(methodBody.Syntax), methodBodyFactory); }
private AsyncRewriter( BoundStatement body, MethodSymbol method, AsyncStateMachine stateMachineClass, TypeCompilationState compilationState, DiagnosticBag diagnostics) : base(body, method, stateMachineClass, compilationState, diagnostics) { try { constructedSuccessfully = AsyncMethodBuilderMemberCollection.TryCreate(F, method, this.stateMachineClass.TypeMap, out this.asyncMethodBuilderMemberCollection); } catch (SyntheticBoundNodeFactory.MissingPredefinedMember ex) { diagnostics.Add(ex.Diagnostic); constructedSuccessfully = false; } }
public override BoundStatement InstrumentForEachStatementDeconstructionVariablesDeclaration(BoundForEachStatement original, BoundStatement iterationVarDecl) { return(Previous.InstrumentForEachStatementDeconstructionVariablesDeclaration(original, iterationVarDecl)); }
public override BoundNode VisitTryStatement(BoundTryStatement node) { var oldDispatches = _dispatches; var oldFinalizerState = _currentFinalizerState; var oldHasFinalizerState = _hasFinalizerState; _dispatches = null; _currentFinalizerState = -1; _hasFinalizerState = false; BoundBlock tryBlock = F.Block((BoundStatement)this.Visit(node.TryBlock)); GeneratedLabelSymbol dispatchLabel = null; if (_dispatches != null) { dispatchLabel = F.GenerateLabel("tryDispatch"); if (_hasFinalizerState) { // cause the current finalizer state to arrive here and then "return false" var finalizer = F.GenerateLabel("finalizer"); _dispatches.Add(finalizer, new List <int>() { _currentFinalizerState }); var skipFinalizer = F.GenerateLabel("skipFinalizer"); tryBlock = F.Block( F.HiddenSequencePoint(), Dispatch(), F.Goto(skipFinalizer), F.Label(finalizer), // code for the finalizer here GenerateSetBothStates(StateMachineStates.NotStartedStateMachine), GenerateReturn(false), F.Label(skipFinalizer), tryBlock); } else { tryBlock = F.Block( F.HiddenSequencePoint(), Dispatch(), tryBlock); } if (oldDispatches == null) { Debug.Assert(!oldHasFinalizerState); oldDispatches = new Dictionary <LabelSymbol, List <int> >(); } oldDispatches.Add(dispatchLabel, new List <int>(from kv in _dispatches.Values from n in kv orderby n select n)); } _hasFinalizerState = oldHasFinalizerState; _currentFinalizerState = oldFinalizerState; _dispatches = oldDispatches; ImmutableArray <BoundCatchBlock> catchBlocks = this.VisitList(node.CatchBlocks); BoundBlock finallyBlockOpt = node.FinallyBlockOpt == null ? null : F.Block( F.HiddenSequencePoint(), F.If( condition: ShouldEnterFinallyBlock(), thenClause: VisitFinally(node.FinallyBlockOpt) ), F.HiddenSequencePoint()); BoundStatement result = node.Update(tryBlock, catchBlocks, finallyBlockOpt, node.FinallyLabelOpt, node.PreferFaultHandler); if ((object)dispatchLabel != null) { result = F.Block( F.HiddenSequencePoint(), F.Label(dispatchLabel), result); } return(result); }
public override BoundNode VisitFixedStatement(BoundFixedStatement node) { ImmutableArray <BoundLocalDeclaration> localDecls = node.Declarations.LocalDeclarations; int numFixedLocals = localDecls.Length; var localBuilder = ArrayBuilder <LocalSymbol> .GetInstance(node.Locals.Length); localBuilder.AddRange(node.Locals); var statementBuilder = ArrayBuilder <BoundStatement> .GetInstance(numFixedLocals + 1 + 1); //+1 for body, +1 for hidden seq point var cleanup = new BoundStatement[numFixedLocals]; for (int i = 0; i < numFixedLocals; i++) { BoundLocalDeclaration localDecl = localDecls[i]; LocalSymbol pinnedTemp; statementBuilder.Add(InitializeFixedStatementLocal(localDecl, _factory, out pinnedTemp)); localBuilder.Add(pinnedTemp); // NOTE: Dev10 nulls out the locals in declaration order (as opposed to "popping" them in reverse order). if (pinnedTemp.RefKind == RefKind.None) { // temp = null; cleanup[i] = _factory.Assignment(_factory.Local(pinnedTemp), _factory.Null(pinnedTemp.Type)); } else { Debug.Assert(!pinnedTemp.Type.IsManagedType); // temp = ref *default(T*); cleanup[i] = _factory.Assignment(_factory.Local(pinnedTemp), new BoundPointerIndirectionOperator( _factory.Syntax, _factory.Default(new PointerTypeSymbol(pinnedTemp.Type)), pinnedTemp.Type), refKind: RefKind.Ref); } } BoundStatement rewrittenBody = VisitStatement(node.Body); statementBuilder.Add(rewrittenBody); statementBuilder.Add(_factory.HiddenSequencePoint()); Debug.Assert(statementBuilder.Count == numFixedLocals + 1 + 1); // In principle, the cleanup code (i.e. nulling out the pinned variables) is always // in a finally block. However, we can optimize finally away (keeping the cleanup // code) in cases where both of the following are true: // 1) there are no branches out of the fixed statement; and // 2) the fixed statement is not in a try block (syntactic or synthesized). if (IsInTryBlock(node) || HasGotoOut(rewrittenBody)) { return(_factory.Block( localBuilder.ToImmutableAndFree(), new BoundTryStatement( _factory.Syntax, _factory.Block(statementBuilder.ToImmutableAndFree()), ImmutableArray <BoundCatchBlock> .Empty, _factory.Block(cleanup)))); } else { statementBuilder.AddRange(cleanup); return(_factory.Block(localBuilder.ToImmutableAndFree(), statementBuilder.ToImmutableAndFree())); } }
/// <summary> /// fixed(int* ptr = arr){ ... } == becomes ===> /// /// pinned int[] pinnedTemp = arr; // pinning managed ref /// int* ptr = pinnedTemp != null && pinnedTemp.Length != 0 /// (int*)&pinnedTemp[0]: // unsafe cast to unmanaged ptr /// 0; /// . . . /// </summary> private BoundStatement InitializeFixedStatementArrayLocal( BoundLocalDeclaration localDecl, LocalSymbol localSymbol, BoundFixedLocalCollectionInitializer fixedInitializer, SyntheticBoundNodeFactory factory, out LocalSymbol pinnedTemp) { TypeSymbol localType = localSymbol.Type; BoundExpression initializerExpr = VisitExpression(fixedInitializer.Expression); TypeSymbol initializerType = initializerExpr.Type; pinnedTemp = factory.SynthesizedLocal(initializerType, isPinned: true); ArrayTypeSymbol arrayType = (ArrayTypeSymbol)pinnedTemp.Type; TypeSymbol arrayElementType = arrayType.ElementType; // NOTE: we pin the array, not the pointer. Debug.Assert(pinnedTemp.IsPinned); Debug.Assert(!localSymbol.IsPinned); //(pinnedTemp = array) BoundExpression arrayTempInit = factory.AssignmentExpression(factory.Local(pinnedTemp), initializerExpr); //(pinnedTemp = array) != null BoundExpression notNullCheck = MakeNullCheck(factory.Syntax, arrayTempInit, BinaryOperatorKind.NotEqual); BoundExpression lengthCall; if (arrayType.IsSZArray) { lengthCall = factory.ArrayLength(factory.Local(pinnedTemp)); } else { MethodSymbol lengthMethod; if (TryGetWellKnownTypeMember(fixedInitializer.Syntax, WellKnownMember.System_Array__get_Length, out lengthMethod)) { lengthCall = factory.Call(factory.Local(pinnedTemp), lengthMethod); } else { lengthCall = new BoundBadExpression(fixedInitializer.Syntax, LookupResultKind.NotInvocable, ImmutableArray <Symbol> .Empty, ImmutableArray.Create <BoundExpression>(factory.Local(pinnedTemp)), ErrorTypeSymbol.UnknownResultType); } } // NOTE: dev10 comment says ">", but code actually checks "!=" //temp.Length != 0 BoundExpression lengthCheck = factory.Binary(BinaryOperatorKind.IntNotEqual, factory.SpecialType(SpecialType.System_Boolean), lengthCall, factory.Literal(0)); //((temp = array) != null && temp.Length != 0) BoundExpression condition = factory.Binary(BinaryOperatorKind.LogicalBoolAnd, factory.SpecialType(SpecialType.System_Boolean), notNullCheck, lengthCheck); //temp[0] BoundExpression firstElement = factory.ArrayAccessFirstElement(factory.Local(pinnedTemp)); // NOTE: this is a fixed statement address-of in that it's the initial value of the pointer. //&temp[0] BoundExpression firstElementAddress = new BoundAddressOfOperator(factory.Syntax, firstElement, type: new PointerTypeSymbol(arrayElementType)); BoundExpression convertedFirstElementAddress = factory.Convert( localType, firstElementAddress, fixedInitializer.ElementPointerTypeConversion); //loc = &temp[0] BoundExpression consequenceAssignment = factory.AssignmentExpression(factory.Local(localSymbol), convertedFirstElementAddress); //loc = null BoundExpression alternativeAssignment = factory.AssignmentExpression(factory.Local(localSymbol), factory.Null(localType)); //(((temp = array) != null && temp.Length != 0) ? loc = &temp[0] : loc = null) BoundStatement localInit = factory.ExpressionStatement( new BoundConditionalOperator(factory.Syntax, false, condition, consequenceAssignment, alternativeAssignment, ConstantValue.NotAvailable, localType)); return(InstrumentLocalDeclarationIfNecessary(localDecl, localSymbol, localInit)); }
public override BoundStatement CreateBlockPrologue(BoundBlock original, out LocalSymbol synthesizedLocal) { BoundStatement previousPrologue = base.CreateBlockPrologue(original, out synthesizedLocal); if (_methodBody == original) { _dynamicAnalysisSpans = _spansBuilder.ToImmutableAndFree(); // In the future there will be multiple analysis kinds. const int analysisKind = 0; ArrayTypeSymbol modulePayloadType = ArrayTypeSymbol.CreateCSharpArray(_methodBodyFactory.Compilation.Assembly, _payloadType); // Synthesize the initialization of the instrumentation payload array, using concurrency-safe code: // // var payload = PID.PayloadRootField[methodIndex]; // if (payload == null) // payload = Instrumentation.CreatePayload(mvid, methodIndex, fileIndexOrIndices, ref PID.PayloadRootField[methodIndex], payloadLength); BoundStatement payloadInitialization = _methodBodyFactory.Assignment( _methodBodyFactory.Local(_methodPayload), _methodBodyFactory.ArrayAccess( _methodBodyFactory.InstrumentationPayloadRoot(analysisKind, modulePayloadType), ImmutableArray.Create(_methodBodyFactory.MethodDefIndex(_method)))); BoundExpression mvid = _methodBodyFactory.ModuleVersionId(); BoundExpression methodToken = _methodBodyFactory.MethodDefIndex(_method); BoundExpression payloadSlot = _methodBodyFactory.ArrayAccess( _methodBodyFactory.InstrumentationPayloadRoot(analysisKind, modulePayloadType), ImmutableArray.Create(_methodBodyFactory.MethodDefIndex(_method))); BoundStatement createPayloadCall = GetCreatePayloadStatement( _dynamicAnalysisSpans, _methodBody.Syntax, _methodPayload, _createPayloadForMethodsSpanningSingleFile, _createPayloadForMethodsSpanningMultipleFiles, mvid, methodToken, payloadSlot, _methodBodyFactory, _debugDocumentProvider); BoundExpression payloadNullTest = _methodBodyFactory.Binary( BinaryOperatorKind.ObjectEqual, _methodBodyFactory.SpecialType(SpecialType.System_Boolean), _methodBodyFactory.Local(_methodPayload), _methodBodyFactory.Null(_payloadType)); BoundStatement payloadIf = _methodBodyFactory.If(payloadNullTest, createPayloadCall); Debug.Assert(synthesizedLocal == null); synthesizedLocal = _methodPayload; ArrayBuilder <BoundStatement> prologueStatements = ArrayBuilder <BoundStatement> .GetInstance(previousPrologue == null? 3 : 4); prologueStatements.Add(payloadInitialization); prologueStatements.Add(payloadIf); if (_methodEntryInstrumentation != null) { prologueStatements.Add(_methodEntryInstrumentation); } if (previousPrologue != null) { prologueStatements.Add(previousPrologue); } return(_methodBodyFactory.StatementList(prologueStatements.ToImmutableAndFree())); } return(previousPrologue); }
public override BoundStatement InstrumentExpressionStatement(BoundExpressionStatement original, BoundStatement rewritten) { return(Previous.InstrumentExpressionStatement(original, rewritten)); }
public override BoundStatement InstrumentLockTargetCapture(BoundLockStatement original, BoundStatement lockTargetCapture) { return(AddDynamicAnalysis(original, base.InstrumentLockTargetCapture(original, lockTargetCapture))); }
public override BoundStatement InstrumentLockTargetCapture(BoundLockStatement original, BoundStatement lockTargetCapture) { return(Previous.InstrumentLockTargetCapture(original, lockTargetCapture)); }
public override BoundStatement InstrumentSwitchWhenClauseConditionalGotoBody(BoundExpression original, BoundStatement ifConditionGotoBody) { return(Previous.InstrumentSwitchWhenClauseConditionalGotoBody(original, ifConditionGotoBody)); }
public override BoundStatement InstrumentUsingTargetCapture(BoundUsingStatement original, BoundStatement usingTargetCapture) { return(Previous.InstrumentUsingTargetCapture(original, usingTargetCapture)); }
public override BoundStatement InstrumentWhileStatementConditionalGotoStartOrBreak(BoundWhileStatement original, BoundStatement ifConditionGotoStart) { return(Previous.InstrumentWhileStatementConditionalGotoStartOrBreak(original, ifConditionGotoStart)); }
public override BoundExpression InstrumentSwitchStatementExpression(BoundStatement original, BoundExpression rewrittenExpression, SyntheticBoundNodeFactory factory) { return(Previous.InstrumentSwitchStatementExpression(original, rewrittenExpression, factory)); }
public override BoundStatement InstrumentDoStatementConditionalGotoStart(BoundDoStatement original, BoundStatement ifConditionGotoStart) { return(Previous.InstrumentDoStatementConditionalGotoStart(original, ifConditionGotoStart)); }
public override BoundStatement InstrumentWhileStatementConditionalGotoStartOrBreak(BoundWhileStatement original, BoundStatement ifConditionGotoStart) { return(AddDynamicAnalysis(original, base.InstrumentWhileStatementConditionalGotoStartOrBreak(original, ifConditionGotoStart))); }
public override BoundStatement InstrumentReturnStatement(BoundReturnStatement original, BoundStatement rewritten) { rewritten = base.InstrumentReturnStatement(original, rewritten); // A synthesized return statement that does not return a value never requires instrumentation. // A property set defined without a block has such a synthesized return statement. // A synthesized return statement that does return a value does require instrumentation. // A method, property get, or lambda defined without a block has such a synthesized return statement. if (ReturnsValueWithinExpressionBodiedConstruct(original)) { // The return statement for value-returning methods defined without a block is compiler generated, but requires instrumentation. return(CollectDynamicAnalysis(original, rewritten)); } return(AddDynamicAnalysis(original, rewritten)); }
public override BoundStatement InstrumentYieldReturnStatement(BoundYieldReturnStatement original, BoundStatement rewritten) { return(AddDynamicAnalysis(original, base.InstrumentYieldReturnStatement(original, rewritten))); }
public override BoundStatement InstrumentLocalInitialization(BoundLocalDeclaration original, BoundStatement rewritten) { return(AddDynamicAnalysis(original, base.InstrumentLocalInitialization(original, rewritten))); }
public override BoundStatement InstrumentFieldOrPropertyInitializer(BoundStatement original, BoundStatement rewritten) { return(Previous.InstrumentFieldOrPropertyInitializer(original, rewritten)); }
public override BoundStatement InstrumentForEachStatementDeconstructionVariablesDeclaration(BoundForEachStatement original, BoundStatement iterationVarDecl) { return(AddDynamicAnalysis(original, base.InstrumentForEachStatementDeconstructionVariablesDeclaration(original, iterationVarDecl))); }
public override BoundStatement InstrumentLocalInitialization(BoundLocalDeclaration original, BoundStatement rewritten) { return(Previous.InstrumentLocalInitialization(original, rewritten)); }
public override BoundStatement InstrumentFieldOrPropertyInitializer(BoundStatement original, BoundStatement rewritten) { return(AddDynamicAnalysis(original, base.InstrumentFieldOrPropertyInitializer(original, rewritten))); }
public override BoundStatement InstrumentForEachStatementConditionalGotoStart(BoundForEachStatement original, BoundStatement branchBack) { return(Previous.InstrumentForEachStatementConditionalGotoStart(original, branchBack)); }
private void GenerateEnumerableImplementation(ref BoundExpression managedThreadId) { var IEnumerable_GetEnumerator = F.SpecialMethod(SpecialMember.System_Collections_IEnumerable__GetEnumerator); var IEnumerableOfElementType = F.SpecialType(SpecialType.System_Collections_Generic_IEnumerable_T).Construct(elementType); var IEnumerableOfElementType_GetEnumerator = F.SpecialMethod(SpecialMember.System_Collections_Generic_IEnumerable_T__GetEnumerator).AsMember(IEnumerableOfElementType); // generate the code for GetEnumerator() // .NET Core has removed the Thread class. We can the managed thread id by making a call to // Environment.CurrentManagedThreadId. If that method is not present (pre 4.5) fall back to the old behavior. // IEnumerable<elementType> result; // if (this.initialThreadId == Thread.CurrentThread.ManagedThreadId && this.state == -2) // { // this.state = 0; // result = this; // } // else // { // result = new Ints0_Impl(0); // } // result.parameter = this.parameterProxy; // copy all of the parameter proxies // Add IEnumerator<elementType> IEnumerable<elementType>.GetEnumerator() // The implementation doesn't depend on the method body of the iterator method. // Only on it's parameters and staticness. var getEnumeratorGeneric = OpenMethodImplementation(IEnumerableOfElementType_GetEnumerator, debuggerHidden: true, hasMethodBodyDependency: false); var bodyBuilder = ArrayBuilder <BoundStatement> .GetInstance(); var resultVariable = F.SynthesizedLocal(stateMachineClass, null); // iteratorClass result; BoundStatement makeIterator = F.Assignment(F.Local(resultVariable), F.New(stateMachineClass.Constructor, F.Literal(0))); // result = new IteratorClass(0) var thisInitialized = F.GenerateLabel("thisInitialized"); if ((object)initialThreadIdField != null) { MethodSymbol currentManagedThreadIdMethod = null; PropertySymbol currentManagedThreadIdProperty = F.WellKnownMember(WellKnownMember.System_Environment__CurrentManagedThreadId, isOptional: true) as PropertySymbol; if ((object)currentManagedThreadIdProperty != null) { currentManagedThreadIdMethod = currentManagedThreadIdProperty.GetMethod; } if ((object)currentManagedThreadIdMethod != null) { managedThreadId = F.Call(null, currentManagedThreadIdMethod); } else { managedThreadId = F.Property(F.Property(WellKnownMember.System_Threading_Thread__CurrentThread), WellKnownMember.System_Threading_Thread__ManagedThreadId); } makeIterator = F.If( condition: F.LogicalAnd( // if (this.state == -2 && this.initialThreadId == Thread.CurrentThread.ManagedThreadId) F.IntEqual(F.Field(F.This(), stateField), F.Literal(StateMachineStates.FinishedStateMachine)), F.IntEqual(F.Field(F.This(), initialThreadIdField), managedThreadId)), thenClause: F.Block( // then F.Assignment(F.Field(F.This(), stateField), F.Literal(StateMachineStates.FirstUnusedState)), // this.state = 0; F.Assignment(F.Local(resultVariable), F.This()), // result = this; method.IsStatic || method.ThisParameter.Type.IsReferenceType ? // if this is a reference type, no need to copy it since it is not assignable F.Goto(thisInitialized) : // goto thisInitialized (BoundStatement)F.Block()), elseClause: makeIterator // else result = new IteratorClass(0) ); } bodyBuilder.Add(makeIterator); // Initialize all the parameter copies var copySrc = initialParameters; var copyDest = variableProxies; if (!method.IsStatic) { // starting with "this" CapturedSymbolReplacement proxy; if (copyDest.TryGetValue(method.ThisParameter, out proxy)) { bodyBuilder.Add( F.Assignment( proxy.Replacement(F.Syntax, stateMachineType => F.Local(resultVariable)), copySrc[method.ThisParameter].Replacement(F.Syntax, stateMachineType => F.This()))); } } bodyBuilder.Add(F.Label(thisInitialized)); foreach (var parameter in method.Parameters) { CapturedSymbolReplacement proxy; if (copyDest.TryGetValue(parameter, out proxy)) { bodyBuilder.Add( F.Assignment( proxy.Replacement(F.Syntax, stateMachineType => F.Local(resultVariable)), copySrc[parameter].Replacement(F.Syntax, stateMachineType => F.This()))); } } bodyBuilder.Add(F.Return(F.Local(resultVariable))); F.CloseMethod(F.Block(ImmutableArray.Create(resultVariable), bodyBuilder.ToImmutableAndFree())); // Generate IEnumerable.GetEnumerator var getEnumerator = OpenMethodImplementation(IEnumerable_GetEnumerator, debuggerHidden: true); F.CloseMethod(F.Return(F.Call(F.This(), getEnumeratorGeneric))); }
public override BoundStatement InstrumentUsingTargetCapture(BoundUsingStatement original, BoundStatement usingTargetCapture) { return(AddDynamicAnalysis(original, base.InstrumentUsingTargetCapture(original, usingTargetCapture))); }
/// <summary> /// fixed(char* ptr = stringVar){ ... } == becomes ===> /// /// pinned string pinnedTemp = stringVar; // pinning managed ref /// char* ptr = (char*)pinnedTemp; // unsafe cast to unmanaged ptr /// if (pinnedTemp != null) ptr += OffsetToStringData(); /// . . . /// </summary> private BoundStatement InitializeFixedStatementStringLocal( BoundLocalDeclaration localDecl, LocalSymbol localSymbol, BoundFixedLocalCollectionInitializer fixedInitializer, SyntheticBoundNodeFactory factory, out LocalSymbol pinnedTemp) { TypeSymbol localType = localSymbol.Type; BoundExpression initializerExpr = VisitExpression(fixedInitializer.Expression); TypeSymbol initializerType = initializerExpr.Type; // intervening parens may have been skipped by the binder; find the declarator VariableDeclaratorSyntax declarator = fixedInitializer.Syntax.FirstAncestorOrSelf <VariableDeclaratorSyntax>(); Debug.Assert(declarator != null); pinnedTemp = factory.SynthesizedLocal( initializerType, syntax: declarator, isPinned: true, kind: SynthesizedLocalKind.FixedReference); // NOTE: we pin the string, not the pointer. Debug.Assert(pinnedTemp.IsPinned); Debug.Assert(!localSymbol.IsPinned); BoundStatement stringTempInit = factory.Assignment(factory.Local(pinnedTemp), initializerExpr); // (char*)pinnedTemp; var addr = factory.Convert( fixedInitializer.ElementPointerType, factory.Local(pinnedTemp), Conversion.PinnedObjectToPointer); var convertedStringTemp = factory.Convert( localType, addr, fixedInitializer.ElementPointerTypeConversion); BoundStatement localInit = InstrumentLocalDeclarationIfNecessary(localDecl, localSymbol, factory.Assignment(factory.Local(localSymbol), convertedStringTemp)); BoundExpression notNullCheck = MakeNullCheck(factory.Syntax, factory.Local(localSymbol), BinaryOperatorKind.NotEqual); BoundExpression helperCall; MethodSymbol offsetMethod; if (TryGetWellKnownTypeMember(fixedInitializer.Syntax, WellKnownMember.System_Runtime_CompilerServices_RuntimeHelpers__get_OffsetToStringData, out offsetMethod)) { helperCall = factory.Call(receiver: null, method: offsetMethod); } else { helperCall = new BoundBadExpression(fixedInitializer.Syntax, LookupResultKind.NotInvocable, ImmutableArray <Symbol> .Empty, ImmutableArray <BoundExpression> .Empty, ErrorTypeSymbol.UnknownResultType); } BoundExpression addition = factory.Binary(BinaryOperatorKind.PointerAndIntAddition, localType, factory.Local(localSymbol), helperCall); BoundStatement conditionalAdd = factory.If(notNullCheck, factory.Assignment(factory.Local(localSymbol), addition)); return(factory.Block(stringTempInit, localInit, conditionalAdd)); }
public override BoundStatement InstrumentPatternSwitchWhenClauseConditionalGotoBody(BoundExpression original, BoundStatement ifConditionGotoBody) { ifConditionGotoBody = base.InstrumentPatternSwitchWhenClauseConditionalGotoBody(original, ifConditionGotoBody); WhenClauseSyntax whenClause = original.Syntax.FirstAncestorOrSelf <WhenClauseSyntax>(); Debug.Assert(whenClause != null); // Instrument the statement using a factory with the same syntax as the clause, so that the instrumentation appears to be part of the clause. SyntheticBoundNodeFactory statementFactory = new SyntheticBoundNodeFactory(_method, whenClause, _methodBodyFactory.CompilationState, _diagnostics); // Instrument using the span of the expression return(statementFactory.StatementList(AddAnalysisPoint(whenClause, statementFactory), ifConditionGotoBody)); }
public override BoundNode VisitTypeOrInstanceInitializers(BoundTypeOrInstanceInitializers node) { ImmutableArray <BoundStatement> originalStatements = node.Statements; ArrayBuilder <BoundStatement> statements = ArrayBuilder <BoundStatement> .GetInstance(node.Statements.Length); foreach (var initializer in originalStatements) { if (IsFieldOrPropertyInitializer(initializer)) { if (initializer.Kind == BoundKind.Block) { var block = (BoundBlock)initializer; statements.Add(block.Update(block.Locals, block.LocalFunctions, ImmutableArray.Create(RewriteExpressionStatement((BoundExpressionStatement)block.Statements.Single(), suppressInstrumentation: true)))); } else { statements.Add(RewriteExpressionStatement((BoundExpressionStatement)initializer, suppressInstrumentation: true)); } } else { statements.Add(VisitStatement(initializer)); } } int optimizedInitializers = 0; bool optimize = _compilation.Options.OptimizationLevel == OptimizationLevel.Release; for (int i = 0; i < statements.Count; i++) { if (statements[i] == null || (optimize && IsFieldOrPropertyInitializer(originalStatements[i]) && ShouldOptimizeOutInitializer(statements[i]))) { optimizedInitializers++; if (!_factory.CurrentFunction.IsStatic) { // NOTE: Dev11 removes static initializers if ONLY all of them are optimized out statements[i] = null; } } } ImmutableArray <BoundStatement> rewrittenStatements; if (optimizedInitializers == statements.Count) { // all are optimized away rewrittenStatements = ImmutableArray <BoundStatement> .Empty; statements.Free(); } else { // instrument remaining statements int remaining = 0; for (int i = 0; i < statements.Count; i++) { BoundStatement rewritten = statements[i]; if (rewritten != null) { if (IsFieldOrPropertyInitializer(originalStatements[i])) { BoundStatement original = originalStatements[i]; if (Instrument && !original.WasCompilerGenerated) { rewritten = _instrumenter.InstrumentFieldOrPropertyInitializer(original, rewritten); } } statements[remaining] = rewritten; remaining++; } } statements.Count = remaining; rewrittenStatements = statements.ToImmutableAndFree(); } return(new BoundStatementList(node.Syntax, rewrittenStatements, node.HasErrors)); }
public override BoundStatement InstrumentPatternSwitchStatement(BoundPatternSwitchStatement original, BoundStatement rewritten) { return(AddDynamicAnalysis(original, base.InstrumentPatternSwitchStatement(original, rewritten))); }
public override BoundStatement InstrumentBreakStatement(BoundBreakStatement original, BoundStatement rewritten) { return(Previous.InstrumentBreakStatement(original, rewritten)); }
public override BoundStatement InstrumentSwitchBindCasePatternVariables(BoundStatement bindings) { return(Previous.InstrumentSwitchBindCasePatternVariables(bindings)); }