示例#1
0
        /// <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);
        }
示例#3
0
        /// <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();
        }
示例#4
0
        /// <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();
        }
示例#5
0
        // 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;
 }
示例#13
0
            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());
            }
        }
示例#16
0
        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;
        }
示例#18
0
 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;
        }
示例#20
0
        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;
        }
示例#23
0
 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);
 }
示例#29
0
        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 &amp;&amp; pinnedTemp.Length != 0
        ///                (int*)&amp;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));
 }
示例#53
0
        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));
        }
示例#57
0
        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));
 }