public override BoundNode VisitReturnStatement(BoundReturnStatement node)
        {
            EnterStatement(node);

            BoundSpillSequenceBuilder builder = null;
            var expression = VisitExpression(ref builder, node.ExpressionOpt);

            return(UpdateStatement(builder, node.Update(expression), substituteTemps: true));
        }
        public override BoundNode VisitReturnStatement(BoundReturnStatement node)
        {
            BoundExpression expression = (BoundExpression)this.Visit(node.ExpressionOpt);

            if (expression == null || expression.Kind != BoundKind.SpillSequence)
            {
                return node.Update(expression);
            }

            var spillSeq = (BoundSpillSequence)expression;
            return RewriteSpillSequenceAsBlock(spillSeq, node.Update(spillSeq.Value));
        }
        public override BoundStatement InstrumentReturnStatement(BoundReturnStatement original, BoundStatement rewritten)
        {
            rewritten = base.InstrumentReturnStatement(original, rewritten);

            if (original.WasCompilerGenerated && original.ExpressionOpt == null && original.Syntax.Kind() == SyntaxKind.Block)
            {
                // implicit return added by the compiler
                return(new BoundSequencePointWithSpan(original.Syntax, rewritten, ((BlockSyntax)original.Syntax).CloseBraceToken.Span));
            }

            return(new BoundSequencePoint(original.Syntax, rewritten));
        }
        public override BoundNode VisitReturnStatement(BoundReturnStatement node)
        {
            if (node.ExpressionOpt != null)
            {
                Debug.Assert(_method.IsGenericTaskReturningAsync(F.Compilation));
                return(F.Block(
                           F.Assignment(F.Local(_exprRetValue), (BoundExpression)Visit(node.ExpressionOpt)),
                           F.Goto(_exprReturnLabel)));
            }

            return(F.Goto(_exprReturnLabel));
        }
        public override BoundNode VisitReturnStatement(BoundReturnStatement node)
        {
            BoundExpression expression = (BoundExpression)this.Visit(node.ExpressionOpt);

            if (expression == null || expression.Kind != BoundKind.SpillSequence)
            {
                return(node.Update(expression));
            }

            var spillSeq = (BoundSpillSequence)expression;

            return(RewriteSpillSequenceAsBlock(spillSeq, node.Update(spillSeq.Value)));
        }
Example #6
0
        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 method defined without a block has such a synthesized return statement.
            if (!_methodHasExplicitBlock && ((BoundReturnStatement)original).ExpressionOpt != null)
            {
                // 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));
        }
Example #7
0
        /// <summary>
        /// Construct a body for an auto-property accessor (updating or returning the backing field).
        /// </summary>
        internal static BoundBlock ConstructAutoPropertyAccessorBody(SourceMethodSymbol accessor)
        {
            Debug.Assert(accessor.MethodKind == MethodKind.PropertyGet || accessor.MethodKind == MethodKind.PropertySet);

            var property                   = (SourcePropertySymbol)accessor.AssociatedSymbol;
            CSharpSyntaxNode syntax        = property.CSharpSyntaxNode;
            BoundExpression  thisReference = null;

            if (!accessor.IsStatic)
            {
                var thisSymbol = accessor.ThisParameter;
                thisReference = new BoundThisReference(syntax, thisSymbol.Type)
                {
                    WasCompilerGenerated = true
                };
            }

            var field       = property.BackingField;
            var fieldAccess = new BoundFieldAccess(syntax, thisReference, field, ConstantValue.NotAvailable)
            {
                WasCompilerGenerated = true
            };
            BoundStatement statement;

            if (accessor.MethodKind == MethodKind.PropertyGet)
            {
                statement = new BoundReturnStatement(accessor.SyntaxNode, RefKind.None, fieldAccess);
            }
            else
            {
                Debug.Assert(accessor.MethodKind == MethodKind.PropertySet);
                var parameter = accessor.Parameters[0];
                statement = new BoundExpressionStatement(
                    accessor.SyntaxNode,
                    new BoundAssignmentOperator(
                        syntax,
                        fieldAccess,
                        new BoundParameter(syntax, parameter)
                {
                    WasCompilerGenerated = true
                },
                        property.Type)
                {
                    WasCompilerGenerated = true
                });
            }

            return(BoundBlock.SynthesizedNoLocals(syntax, statement));
        }
        public override BoundNode VisitReturnStatement(BoundReturnStatement node)
        {
            BoundStatement rewritten = (BoundStatement)base.VisitReturnStatement(node);

            // NOTE: we will apply sequence points to synthesized return statements if they are contained in lambdas and have expressions.
            // We do this to ensure that expression lambdas have sequence points, as in Dev10.
            if (this.generateDebugInfo &&
                (!rewritten.WasCompilerGenerated || (node.ExpressionOpt != null && this.factory.CurrentMethod is LambdaSymbol)))
            {
                // We're not calling AddSequencePoint since it ignores compiler-generated nodes.
                return new BoundSequencePoint(rewritten.Syntax, rewritten);
            }

            return rewritten;
        }
Example #9
0
        public override BoundNode VisitReturnStatement(BoundReturnStatement node)
        {
            BoundStatement rewritten = (BoundStatement)base.VisitReturnStatement(node);

            // NOTE: we will apply sequence points to synthesized return statements if they are contained in lambdas and have expressions.
            // We do this to ensure that expression lambdas have sequence points, as in Dev10.
            if (this.generateDebugInfo &&
                (!rewritten.WasCompilerGenerated || (node.ExpressionOpt != null && this.factory.CurrentMethod is LambdaSymbol)))
            {
                // We're not calling AddSequencePoint since it ignores compiler-generated nodes.
                return(new BoundSequencePoint(rewritten.Syntax, rewritten));
            }

            return(rewritten);
        }
Example #10
0
        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));
        }
Example #11
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(BoundBlock body, MethodSymbol method)
        {
            Debug.Assert(body != null);
            Debug.Assert(method != null);

            SyntaxNode syntax = body.Syntax;

            Debug.Assert(body.WasCompilerGenerated ||
                         syntax.IsKind(SyntaxKind.Block) ||
                         syntax.IsKind(SyntaxKind.ArrowExpressionClause) ||
                         syntax.IsKind(SyntaxKind.ConstructorDeclaration));

            BoundStatement ret = (method.IsIterator && !method.IsAsync)
                ? (BoundStatement)BoundYieldBreakStatement.Synthesized(syntax)
                : BoundReturnStatement.Synthesized(syntax, RefKind.None, null);

            return(body.Update(body.Locals, body.LocalFunctions, body.Statements.Add(ret)));
        }
Example #12
0
        private static bool ReturnsValueWithinExpressionBodiedConstruct(BoundReturnStatement returnStatement)
        {
            if (returnStatement.WasCompilerGenerated &&
                returnStatement.ExpressionOpt != null &&
                returnStatement.ExpressionOpt.Syntax != null)
            {
                SyntaxKind parentKind = returnStatement.ExpressionOpt.Syntax.Parent.Kind();
                switch (parentKind)
                {
                case SyntaxKind.ParenthesizedLambdaExpression:
                case SyntaxKind.SimpleLambdaExpression:
                case SyntaxKind.ArrowExpressionClause:
                    return(true);
                }
            }

            return(false);
        }
        public override BoundNode VisitReturnStatement(BoundReturnStatement node)
        {
            BoundStatement rewritten = (BoundStatement)base.VisitReturnStatement(node);

            // NOTE: we will apply sequence points to synthesized return 
            // statements if they are contained in lambdas and have expressions
            // or if they are expression-bodied properties.
            // We do this to ensure that expression lambdas and expression-bodied
            // properties have sequence points.
            if (this.GenerateDebugInfo &&
                (!rewritten.WasCompilerGenerated || 
                 (node.ExpressionOpt != null && IsLambdaOrExpressionBodiedMember)))
            {
                // We're not calling AddSequencePoint since it ignores compiler-generated nodes.
                return new BoundSequencePoint(rewritten.Syntax, rewritten);
            }

            return rewritten;
        }
Example #14
0
        public override BoundNode VisitReturnStatement(BoundReturnStatement node)
        {
            BoundStatement rewritten = (BoundStatement)base.VisitReturnStatement(node);

            // NOTE: we will apply sequence points to synthesized return
            // statements if they are contained in lambdas and have expressions
            // or if they are expression-bodied properties.
            // We do this to ensure that expression lambdas and expression-bodied
            // properties have sequence points.
            if (this.GenerateDebugInfo &&
                (!rewritten.WasCompilerGenerated ||
                 (node.ExpressionOpt != null && IsLambdaOrExpressionBodiedMember)))
            {
                // We're not calling AddSequencePoint since it ignores compiler-generated nodes.
                return(new BoundSequencePoint(rewritten.Syntax, rewritten));
            }

            return(rewritten);
        }
Example #15
0
            public override BoundNode VisitReturnStatement(BoundReturnStatement node)
            {
                var expression = node.ExpressionOpt;

                if (expression != null)
                {
                    var returnType = expression.Type;
                    // This is potentially inefficient if there are a large number of returns each with
                    // a different type. This seems unlikely.
                    if (!types.Contains(returnType))
                    {
                        types.Add(returnType);
                    }
                }
                else
                {
                    hasReturnWithoutArgument = true;
                }

                return(null);
            }
Example #16
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, CSharpSyntaxNode syntax = null)
        {
            Debug.Assert(method != null);

            if (syntax == null)
            {
                syntax = node.Syntax;
            }

            BoundStatement ret = method.IsIterator
                ? (BoundStatement)BoundYieldBreakStatement.Synthesized(syntax)
                : BoundReturnStatement.Synthesized(syntax, null);

            if (syntax.Kind() == SyntaxKind.Block)
            {
                // Implicitly added return for async method does not need sequence points since lowering would add one.
                if (!method.IsAsync)
                {
                    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.Locals, block.Statements.Add(ret)));

            default:
                return(new BoundBlock(syntax, ImmutableArray <LocalSymbol> .Empty, ImmutableArray.Create(ret, node)));
            }
        }
Example #17
0
        public override BoundNode VisitReturnStatement(BoundReturnStatement node)
        {
            var result = base.VisitReturnStatement(node);

            // After processing a return statement, the very last pending branch is for that return statement.
            // If it is returning an allocated object, consider it to be disposed.

            if (result != null)
            {
                switch (result.Kind)
                {
                case HijackedBoundKindForValueHolder:
                {
                    var holder       = (BoundValueHolder)result;
                    var returnBranch = PendingBranches.Last();
                    foreach (var c in holder.value.creations)
                    {
                        returnBranch.State.possiblyUndisposedCreations.Remove(c);
                        if (returnBranch.State.possiblyDisposedCreations.Contains(c))
                        {
                            // TODO: error: returning a value that may already have been disposed.
                        }
                    }
                    break;
                }

                case BoundKind.NewT:
                case BoundKind.ObjectCreationExpression:
                    PendingBranches.Last().State.possiblyUndisposedCreations.Remove((BoundExpression)result);
                    break;

                default:
                    break;
                }
            }

            return(result);
        }
Example #18
0
        public override BoundNode VisitReturnStatement(BoundReturnStatement node)
        {
            BoundStatement rewritten = (BoundStatement)base.VisitReturnStatement(node);

            // NOTE: we will apply sequence points to synthesized return
            // statements if they are contained in lambdas and have expressions
            // or if they are expression-bodied properties.
            // We do this to ensure that expression lambdas and expression-bodied
            // properties have sequence points.
            // We also add sequence points for the implicit "return" statement at the end of the method body
            // (added by FlowAnalysisPass.AppendImplicitReturn). Implicitly added return for async method
            // does not need sequence points added here since it would be done later (presumably during Async rewrite).
            if (this.Instrument &&
                (!node.WasCompilerGenerated ||
                 (node.ExpressionOpt != null ?
                  IsLambdaOrExpressionBodiedMember :
                  (node.Syntax.Kind() == SyntaxKind.Block && _factory.CurrentMethod?.IsAsync == false))))
            {
                rewritten = _instrumenter.InstrumentReturnStatement(node, rewritten);
            }

            return(rewritten);
        }
        public override BoundNode VisitReturnStatement(BoundReturnStatement node)
        {
            BoundStatement rewritten = (BoundStatement)base.VisitReturnStatement(node);

            // NOTE: we will apply sequence points to synthesized return 
            // statements if they are contained in lambdas and have expressions
            // or if they are expression-bodied properties.
            // We do this to ensure that expression lambdas and expression-bodied
            // properties have sequence points.
            // We also add sequence points for the implicit "return" statement at the end of the method body
            // (added by FlowAnalysisPass.AppendImplicitReturn). Implicitly added return for async method 
            // does not need sequence points added here since it would be done later (presumably during Async rewrite).
            if (this.Instrument &&
                (!node.WasCompilerGenerated ||
                 (node.ExpressionOpt != null ? 
                        IsLambdaOrExpressionBodiedMember :
                        (node.Syntax.Kind() == SyntaxKind.Block && _factory.CurrentMethod?.IsAsync == false))))
            {
                rewritten = _instrumenter.InstrumentReturnStatement(node, rewritten);
            }

            return rewritten;
        }
Example #20
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 <BoundStatement>(ret, node)));
            }
        }
Example #21
0
        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 method defined without a block has such a synthesized return statement.
            if (!_methodHasExplicitBlock && ((BoundReturnStatement)original).ExpressionOpt != null)
            {
                // 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);
        }
        /// <summary>
        /// Generate a thread-safe accessor for a WinRT field-like event.
        /// 
        /// Add:
        ///   return EventRegistrationTokenTable&lt;Event&gt;.GetOrCreateEventRegistrationTokenTable(ref _tokenTable).AddEventHandler(value);
        /// 
        /// Remove:
        ///   EventRegistrationTokenTable&lt;Event&gt;.GetOrCreateEventRegistrationTokenTable(ref _tokenTable).RemoveEventHandler(value);
        /// </summary>
        internal static BoundBlock ConstructFieldLikeEventAccessorBody_WinRT(SourceEventSymbol eventSymbol, bool isAddMethod, CSharpCompilation compilation, DiagnosticBag diagnostics)
        {
            CSharpSyntaxNode syntax = eventSymbol.CSharpSyntaxNode;

            MethodSymbol accessor = isAddMethod ? eventSymbol.AddMethod : eventSymbol.RemoveMethod;
            Debug.Assert((object)accessor != null);

            FieldSymbol field = eventSymbol.AssociatedField;
            Debug.Assert((object)field != null);

            NamedTypeSymbol fieldType = (NamedTypeSymbol)field.Type;
            Debug.Assert(fieldType.Name == "EventRegistrationTokenTable");

            MethodSymbol getOrCreateMethod = (MethodSymbol)Binder.GetWellKnownTypeMember(
                compilation,
                WellKnownMember.System_Runtime_InteropServices_WindowsRuntime_EventRegistrationTokenTable_T__GetOrCreateEventRegistrationTokenTable,
                diagnostics,
                syntax: syntax);

            if ((object)getOrCreateMethod == null)
            {
                Debug.Assert(diagnostics.HasAnyErrors());
                return null;
            }

            getOrCreateMethod = getOrCreateMethod.AsMember(fieldType);

            WellKnownMember processHandlerMember = isAddMethod
                ? WellKnownMember.System_Runtime_InteropServices_WindowsRuntime_EventRegistrationTokenTable_T__AddEventHandler
                : WellKnownMember.System_Runtime_InteropServices_WindowsRuntime_EventRegistrationTokenTable_T__RemoveEventHandler;

            MethodSymbol processHandlerMethod = (MethodSymbol)Binder.GetWellKnownTypeMember(
                compilation,
                processHandlerMember,
                diagnostics,
                syntax: syntax);

            if ((object)processHandlerMethod == null)
            {
                Debug.Assert(diagnostics.HasAnyErrors());
                return null;
            }

            processHandlerMethod = processHandlerMethod.AsMember(fieldType);

            // _tokenTable
            BoundFieldAccess fieldAccess = new BoundFieldAccess(
                syntax,
                field.IsStatic ? null : new BoundThisReference(syntax, accessor.ThisParameter.Type),
                field,
                constantValueOpt: null)
            { WasCompilerGenerated = true };

            // EventRegistrationTokenTable<Event>.GetOrCreateEventRegistrationTokenTable(ref _tokenTable)
            BoundCall getOrCreateCall = BoundCall.Synthesized(
                syntax,
                receiverOpt: null,
                method: getOrCreateMethod,
                arguments: fieldAccess);

            // value
            BoundParameter parameterAccess = new BoundParameter(
                syntax,
                accessor.Parameters.Single());

            // EventRegistrationTokenTable<Event>.GetOrCreateEventRegistrationTokenTable(ref _tokenTable).AddHandler(value) // or RemoveHandler
            BoundCall processHandlerCall = BoundCall.Synthesized(
                syntax,
                receiverOpt: getOrCreateCall,
                method: processHandlerMethod,
                arguments: parameterAccess);

            if (isAddMethod)
            {
                // {
                //     return EventRegistrationTokenTable<Event>.GetOrCreateEventRegistrationTokenTable(ref _tokenTable).AddHandler(value);
                // }   
                BoundStatement returnStatement = BoundReturnStatement.Synthesized(syntax, processHandlerCall);
                return BoundBlock.SynthesizedNoLocals(syntax, returnStatement);
            }
            else
            {
                // {
                //     EventRegistrationTokenTable<Event>.GetOrCreateEventRegistrationTokenTable(ref _tokenTable).RemoveHandler(value);
                //     return;
                // }  
                BoundStatement callStatement = new BoundExpressionStatement(syntax, processHandlerCall);
                BoundStatement returnStatement = new BoundReturnStatement(syntax, expressionOpt: null);
                return BoundBlock.SynthesizedNoLocals(syntax, callStatement, returnStatement);
            }
        }
        /// <summary>
        /// Construct a body for an auto-property accessor (updating or returning the backing field).
        /// </summary>
        internal static BoundBlock ConstructAutoPropertyAccessorBody(SourceMethodSymbol accessor)
        {
            Debug.Assert(accessor.MethodKind == MethodKind.PropertyGet || accessor.MethodKind == MethodKind.PropertySet);

            var property = (SourcePropertySymbol)accessor.AssociatedSymbol;
            CSharpSyntaxNode syntax = property.CSharpSyntaxNode;
            BoundExpression thisReference = null;
            if (!accessor.IsStatic)
            {
                var thisSymbol = accessor.ThisParameter;
                thisReference = new BoundThisReference(syntax, thisSymbol.Type) { WasCompilerGenerated = true };
            }

            var field = property.BackingField;
            var fieldAccess = new BoundFieldAccess(syntax, thisReference, field, ConstantValue.NotAvailable) { WasCompilerGenerated = true };
            BoundStatement statement;

            if (accessor.MethodKind == MethodKind.PropertyGet)
            {
                statement = new BoundReturnStatement(syntax, fieldAccess) { WasCompilerGenerated = true };
            }
            else
            {
                Debug.Assert(accessor.MethodKind == MethodKind.PropertySet);
                var parameter = accessor.Parameters[0];
                statement = new BoundExpressionStatement(
                    syntax,
                    new BoundAssignmentOperator(
                        syntax,
                        fieldAccess,
                        new BoundParameter(syntax, parameter) { WasCompilerGenerated = true },
                        property.Type)
                { WasCompilerGenerated = true })
                { WasCompilerGenerated = true };
            }

            statement = new BoundSequencePoint(accessor.SyntaxNode, statement) { WasCompilerGenerated = true };

            return new BoundBlock(syntax, ImmutableArray<LocalSymbol>.Empty, ImmutableArray.Create<BoundStatement>(statement)) { WasCompilerGenerated = true };
        }
Example #24
0
 public override BoundStatement InstrumentReturnStatement(BoundReturnStatement original, BoundStatement rewritten)
 {
     return Previous.InstrumentReturnStatement(original, rewritten);
 }
        /// <summary>
        /// Generate a thread-safe accessor for a regular field-like event.
        /// 
        /// DelegateType tmp0 = _event; //backing field
        /// DelegateType tmp1;
        /// DelegateType tmp2;
        /// do {
        ///     tmp1 = tmp0;
        ///     tmp2 = (DelegateType)Delegate.Combine(tmp1, value); //Remove for -=
        ///     tmp0 = Interlocked.CompareExchange&lt;DelegateType&gt;(ref _event, tmp2, tmp1);
        /// } while ((object)tmp0 != (object)tmp1);
        /// </summary>
        internal static BoundBlock ConstructFieldLikeEventAccessorBody_Regular(SourceEventSymbol eventSymbol, bool isAddMethod, CSharpCompilation compilation, DiagnosticBag diagnostics)
        {
            CSharpSyntaxNode syntax = eventSymbol.CSharpSyntaxNode;

            TypeSymbol delegateType = eventSymbol.Type;
            MethodSymbol accessor = isAddMethod ? eventSymbol.AddMethod : eventSymbol.RemoveMethod;
            ParameterSymbol thisParameter = accessor.ThisParameter;

            TypeSymbol boolType = compilation.GetSpecialType(SpecialType.System_Boolean);
            MethodSymbol updateMethod = (MethodSymbol)compilation.GetSpecialTypeMember(isAddMethod ? SpecialMember.System_Delegate__Combine : SpecialMember.System_Delegate__Remove);
            MethodSymbol compareExchangeMethod = GetConstructedCompareExchangeMethod(delegateType, compilation, accessor.Locations[0], diagnostics);

            if ((object)compareExchangeMethod == null)
            {
                return new BoundBlock(syntax,
                    locals: ImmutableArray<LocalSymbol>.Empty,
                    statements: ImmutableArray.Create<BoundStatement>(
                        new BoundReturnStatement(syntax,
                            expressionOpt: null)
                { WasCompilerGenerated = true }))
                { WasCompilerGenerated = true };
            }

            GeneratedLabelSymbol loopLabel = new GeneratedLabelSymbol("loop");

            const int numTemps = 3;

            LocalSymbol[] tmps = new LocalSymbol[numTemps];
            BoundLocal[] boundTmps = new BoundLocal[numTemps];

            for (int i = 0; i < numTemps; i++)
            {
                tmps[i] = new SynthesizedLocal(accessor, delegateType, SynthesizedLocalKind.LoweringTemp);
                boundTmps[i] = new BoundLocal(syntax, tmps[i], null, delegateType);
            }

            BoundThisReference fieldReceiver = eventSymbol.IsStatic ?
                null :
                new BoundThisReference(syntax, thisParameter.Type) { WasCompilerGenerated = true };

            BoundFieldAccess boundBackingField = new BoundFieldAccess(syntax,
                receiver: fieldReceiver,
                fieldSymbol: eventSymbol.AssociatedField,
                constantValueOpt: null)
            { WasCompilerGenerated = true };

            BoundParameter boundParameter = new BoundParameter(syntax,
                parameterSymbol: accessor.Parameters[0])
            { WasCompilerGenerated = true };

            // tmp0 = _event;
            BoundStatement tmp0Init = new BoundExpressionStatement(syntax,
                expression: new BoundAssignmentOperator(syntax,
                    left: boundTmps[0],
                    right: boundBackingField,
                    type: delegateType)
            { WasCompilerGenerated = true })
            { WasCompilerGenerated = true };

            // LOOP:
            BoundStatement loopStart = new BoundLabelStatement(syntax,
                label: loopLabel)
            { WasCompilerGenerated = true };

            // tmp1 = tmp0;
            BoundStatement tmp1Update = new BoundExpressionStatement(syntax,
                expression: new BoundAssignmentOperator(syntax,
                    left: boundTmps[1],
                    right: boundTmps[0],
                    type: delegateType)
            { WasCompilerGenerated = true })
            { WasCompilerGenerated = true };

            // (DelegateType)Delegate.Combine(tmp1, value)
            BoundExpression delegateUpdate = BoundConversion.SynthesizedNonUserDefined(syntax,
                operand: BoundCall.Synthesized(syntax,
                    receiverOpt: null,
                    method: updateMethod,
                    arguments: ImmutableArray.Create<BoundExpression>(boundTmps[1], boundParameter)),
                kind: ConversionKind.ExplicitReference,
                type: delegateType);

            // tmp2 = (DelegateType)Delegate.Combine(tmp1, value);
            BoundStatement tmp2Update = new BoundExpressionStatement(syntax,
                expression: new BoundAssignmentOperator(syntax,
                    left: boundTmps[2],
                    right: delegateUpdate,
                    type: delegateType)
            { WasCompilerGenerated = true })
            { WasCompilerGenerated = true };

            // Interlocked.CompareExchange<DelegateType>(ref _event, tmp2, tmp1)
            BoundExpression compareExchange = BoundCall.Synthesized(syntax,
                receiverOpt: null,
                method: compareExchangeMethod,
                arguments: ImmutableArray.Create<BoundExpression>(boundBackingField, boundTmps[2], boundTmps[1]));

            // tmp0 = Interlocked.CompareExchange<DelegateType>(ref _event, tmp2, tmp1);
            BoundStatement tmp0Update = new BoundExpressionStatement(syntax,
                expression: new BoundAssignmentOperator(syntax,
                    left: boundTmps[0],
                    right: compareExchange,
                    type: delegateType)
            { WasCompilerGenerated = true })
            { WasCompilerGenerated = true };

            // tmp0 == tmp1 // i.e. exit when they are equal, jump to start otherwise
            BoundExpression loopExitCondition = new BoundBinaryOperator(syntax,
                operatorKind: BinaryOperatorKind.ObjectEqual,
                left: boundTmps[0],
                right: boundTmps[1],
                constantValueOpt: null,
                methodOpt: null,
                resultKind: LookupResultKind.Viable,
                type: boolType)
            { WasCompilerGenerated = true };
            
            // branchfalse (tmp0 == tmp1) LOOP
            BoundStatement loopEnd = new BoundConditionalGoto(syntax,
                condition: loopExitCondition,
                jumpIfTrue: false,
                label: loopLabel)
            { WasCompilerGenerated = true };

            BoundStatement @return = new BoundReturnStatement(syntax,
                expressionOpt: null)
            { WasCompilerGenerated = true };

            return new BoundBlock(syntax,
                locals: tmps.AsImmutable(),
                statements: ImmutableArray.Create<BoundStatement>(
                    tmp0Init,
                    loopStart,
                    tmp1Update,
                    tmp2Update,
                    tmp0Update,
                    loopEnd,
                    @return))
            { WasCompilerGenerated = true };

        }
        private BoundStatement UnpendBranches(
            AwaitFinallyFrame frame,
            SynthesizedLocal pendingBranchVar,
            SynthesizedLocal pendingException)
        {
            var parent = frame.ParentOpt;

            // handle proxy labels if have any
            var proxiedLabels = frame.proxiedLabels;

            // skip 0 - it means we took no explicit branches
            int i     = 1;
            var cases = ArrayBuilder <BoundSwitchSection> .GetInstance();

            if (proxiedLabels != null)
            {
                for (int cnt = proxiedLabels.Count; i <= cnt; i++)
                {
                    var target        = proxiedLabels[i - 1];
                    var parentProxy   = parent.ProxyLabelIfNeeded(target);
                    var caseStatement = _F.SwitchSection(i, _F.Goto(parentProxy));
                    cases.Add(caseStatement);
                }
            }

            if (frame.returnProxyLabel != null)
            {
                BoundLocal pendingValue = null;
                if (frame.returnValue != null)
                {
                    pendingValue = _F.Local(frame.returnValue);
                }

                SynthesizedLocal returnValue;
                BoundStatement   unpendReturn;

                var returnLabel = parent.ProxyReturnIfNeeded(_F.CurrentFunction, pendingValue, out returnValue);

                if (returnLabel == null)
                {
                    unpendReturn = new BoundReturnStatement(_F.Syntax, RefKind.None, pendingValue);
                }
                else
                {
                    if (pendingValue == null)
                    {
                        unpendReturn = _F.Goto(returnLabel);
                    }
                    else
                    {
                        unpendReturn = _F.Block(
                            _F.Assignment(
                                _F.Local(returnValue),
                                pendingValue),
                            _F.Goto(returnLabel));
                    }
                }

                var caseStatement = _F.SwitchSection(i, unpendReturn);
                cases.Add(caseStatement);
            }

            return(_F.Switch(_F.Local(pendingBranchVar), cases.ToImmutableAndFree()));
        }
Example #27
0
            public override BoundNode VisitReturnStatement(BoundReturnStatement node)
            {
                var expression = node.ExpressionOpt;
                if (expression != null)
                {
                    var returnType = expression.Type;
                    // This is potentially inefficient if there are a large number of returns each with
                    // a different type. This seems unlikely.
                    if (!_types.Contains(returnType))
                    {
                        _types.Add(returnType);
                    }
                }
                else
                {
                    _hasReturnWithoutArgument = true;
                }

                return null;
            }
Example #28
0
        /// <summary>
        /// Generate a thread-safe accessor for a WinRT field-like event.
        ///
        /// Add:
        ///   return EventRegistrationTokenTable&lt;Event&gt;.GetOrCreateEventRegistrationTokenTable(ref _tokenTable).AddEventHandler(value);
        ///
        /// Remove:
        ///   EventRegistrationTokenTable&lt;Event&gt;.GetOrCreateEventRegistrationTokenTable(ref _tokenTable).RemoveEventHandler(value);
        /// </summary>
        internal static BoundBlock ConstructFieldLikeEventAccessorBody_WinRT(SourceEventSymbol eventSymbol, bool isAddMethod, CSharpCompilation compilation, DiagnosticBag diagnostics)
        {
            CSharpSyntaxNode syntax = eventSymbol.CSharpSyntaxNode;

            MethodSymbol accessor = isAddMethod ? eventSymbol.AddMethod : eventSymbol.RemoveMethod;

            Debug.Assert((object)accessor != null);

            FieldSymbol field = eventSymbol.AssociatedField;

            Debug.Assert((object)field != null);

            NamedTypeSymbol fieldType = (NamedTypeSymbol)field.Type;

            Debug.Assert(fieldType.Name == "EventRegistrationTokenTable");

            MethodSymbol getOrCreateMethod = (MethodSymbol)Binder.GetWellKnownTypeMember(
                compilation,
                WellKnownMember.System_Runtime_InteropServices_WindowsRuntime_EventRegistrationTokenTable_T__GetOrCreateEventRegistrationTokenTable,
                diagnostics,
                syntax: syntax);

            if ((object)getOrCreateMethod == null)
            {
                Debug.Assert(diagnostics.HasAnyErrors());
                return(null);
            }

            getOrCreateMethod = getOrCreateMethod.AsMember(fieldType);

            WellKnownMember processHandlerMember = isAddMethod
                ? WellKnownMember.System_Runtime_InteropServices_WindowsRuntime_EventRegistrationTokenTable_T__AddEventHandler
                : WellKnownMember.System_Runtime_InteropServices_WindowsRuntime_EventRegistrationTokenTable_T__RemoveEventHandler;

            MethodSymbol processHandlerMethod = (MethodSymbol)Binder.GetWellKnownTypeMember(
                compilation,
                processHandlerMember,
                diagnostics,
                syntax: syntax);

            if ((object)processHandlerMethod == null)
            {
                Debug.Assert(diagnostics.HasAnyErrors());
                return(null);
            }

            processHandlerMethod = processHandlerMethod.AsMember(fieldType);

            // _tokenTable
            BoundFieldAccess fieldAccess = new BoundFieldAccess(
                syntax,
                field.IsStatic ? null : new BoundThisReference(syntax, accessor.ThisParameter.Type),
                field,
                constantValueOpt: null)
            {
                WasCompilerGenerated = true
            };

            // EventRegistrationTokenTable<Event>.GetOrCreateEventRegistrationTokenTable(ref _tokenTable)
            BoundCall getOrCreateCall = BoundCall.Synthesized(
                syntax,
                receiverOpt: null,
                method: getOrCreateMethod,
                arg0: fieldAccess);

            // value
            BoundParameter parameterAccess = new BoundParameter(
                syntax,
                accessor.Parameters.Single());

            // EventRegistrationTokenTable<Event>.GetOrCreateEventRegistrationTokenTable(ref _tokenTable).AddHandler(value) // or RemoveHandler
            BoundCall processHandlerCall = BoundCall.Synthesized(
                syntax,
                receiverOpt: getOrCreateCall,
                method: processHandlerMethod,
                arg0: parameterAccess);

            if (isAddMethod)
            {
                // {
                //     return EventRegistrationTokenTable<Event>.GetOrCreateEventRegistrationTokenTable(ref _tokenTable).AddHandler(value);
                // }
                BoundStatement returnStatement = BoundReturnStatement.Synthesized(syntax, processHandlerCall);
                return(BoundBlock.SynthesizedNoLocals(syntax, returnStatement));
            }
            else
            {
                // {
                //     EventRegistrationTokenTable<Event>.GetOrCreateEventRegistrationTokenTable(ref _tokenTable).RemoveHandler(value);
                //     return;
                // }
                BoundStatement callStatement   = new BoundExpressionStatement(syntax, processHandlerCall);
                BoundStatement returnStatement = new BoundReturnStatement(syntax, expressionOpt: null);
                return(BoundBlock.SynthesizedNoLocals(syntax, callStatement, returnStatement));
            }
        }
Example #29
0
 public override BoundNode VisitReturnStatement(BoundReturnStatement node)
 {
     BoundSpillSequence2 ss = null;
     var expression = VisitExpression(ref ss, node.ExpressionOpt);
     return UpdateStatement(ss, node.Update(expression));
 }
Example #30
0
        /// <summary>
        /// Wrap a given expression e into a block as either { e; } or { return e; } 
        /// Shared between lambda and expression-bodied method binding.
        /// </summary>
        internal BoundBlock CreateBlockFromExpression(CSharpSyntaxNode node, ImmutableArray<LocalSymbol> locals, RefKind refKind, BoundExpression expression, ExpressionSyntax expressionSyntax, DiagnosticBag diagnostics)
        {
            RefKind returnRefKind;
            var returnType = GetCurrentReturnType(out returnRefKind);
            var syntax = expressionSyntax ?? expression.Syntax;

            BoundStatement statement;
            if (IsInAsyncMethod() && refKind != RefKind.None)
            {
                // This can happen if we are binding an async anonymous method to a delegate type.
                Error(diagnostics, ErrorCode.ERR_MustNotHaveRefReturn, syntax);
                statement = new BoundReturnStatement(syntax, refKind, expression) { WasCompilerGenerated = true };
            }
            else if ((object)returnType != null)
            {
                if ((refKind != RefKind.None) != (returnRefKind != RefKind.None))
                {
                    var errorCode = refKind != RefKind.None
                        ? ErrorCode.ERR_MustNotHaveRefReturn
                        : ErrorCode.ERR_MustHaveRefReturn;
                    Error(diagnostics, errorCode, syntax);
                    statement = new BoundReturnStatement(syntax, RefKind.None, expression) { WasCompilerGenerated = true };
                }
                else if (returnType.SpecialType == SpecialType.System_Void || IsTaskReturningAsyncMethod())
                {
                    // If the return type is void then the expression is required to be a legal
                    // statement expression.

                    Debug.Assert(expressionSyntax != null || !IsValidStatementExpression(expression.Syntax, expression));

                    bool errors = false;
                    if (expressionSyntax == null || !IsValidStatementExpression(expressionSyntax, expression))
                    {
                        Error(diagnostics, ErrorCode.ERR_IllegalStatement, syntax);
                        errors = true;
                    }

                    // Don't mark compiler generated so that the rewriter generates sequence points
                    var expressionStatement = new BoundExpressionStatement(syntax, expression, errors);

                    CheckForUnobservedAwaitable(expression, diagnostics);
                    statement = expressionStatement;
                }
                else
                {
                    expression = CreateReturnConversion(syntax, diagnostics, expression, refKind, returnType);
                    statement = new BoundReturnStatement(syntax, returnRefKind, expression) { WasCompilerGenerated = true };
                }
            }
            else if (expression.Type?.SpecialType == SpecialType.System_Void)
            {
                statement = new BoundExpressionStatement(syntax, expression) { WasCompilerGenerated = true };
            }
            else
            {
                statement = new BoundReturnStatement(syntax, refKind, expression) { WasCompilerGenerated = true };
            }

            // Need to attach the tree for when we generate sequence points.
            return new BoundBlock(node, locals, ImmutableArray<LocalFunctionSymbol>.Empty, ImmutableArray.Create(statement)) { WasCompilerGenerated = node.Kind() != SyntaxKind.ArrowExpressionClause };
        }
Example #31
0
        /// <summary>
        /// Wrap a given expression e into a block as either { e; } or { return e; } 
        /// Shared between lambda and expression-bodied method binding.
        /// </summary>
        internal BoundBlock CreateBlockFromExpression(CSharpSyntaxNode node, ImmutableArray<LocalSymbol> locals, ExpressionSyntax expressionSyntax, BoundExpression expression, DiagnosticBag diagnostics)
        {
            var returnType = GetCurrentReturnType();
            var syntax = expressionSyntax ?? expression.Syntax;

            BoundStatement statement;
            if ((object)returnType != null)
            {
                if (returnType.SpecialType == SpecialType.System_Void || IsTaskReturningAsyncMethod())
                {
                    // If the return type is void then the expression is required to be a legal
                    // statement expression.

                    Debug.Assert(expressionSyntax != null || !IsValidStatementExpression(expression.Syntax, expression));

                    bool errors = false;
                    if (expressionSyntax == null || !IsValidStatementExpression(expressionSyntax, expression))
                    {
                        Error(diagnostics, ErrorCode.ERR_IllegalStatement, syntax);
                        errors = true;
                    }

                    // Don't mark compiler generated so that the rewriter generates sequence points
                    var expressionStatement = new BoundExpressionStatement(syntax, expression, errors);

                    CheckForUnobservedAwaitable(expressionStatement, diagnostics);
                    statement = expressionStatement;
                }
                else
                {
                    expression = CreateReturnConversion(syntax, diagnostics, expression, returnType);
                    statement = new BoundReturnStatement(syntax, expression) { WasCompilerGenerated = true };
                }
            }
            else if (expression.Type?.SpecialType == SpecialType.System_Void)
            {
                statement = new BoundExpressionStatement(syntax, expression) { WasCompilerGenerated = true };
            }
            else
            {
                statement = new BoundReturnStatement(syntax, expression) { WasCompilerGenerated = true };
            }

            // Need to attach the tree for when we generate sequence points.
            return new BoundBlock(node, locals, ImmutableArray.Create(statement)) { WasCompilerGenerated = node.Kind() != SyntaxKind.ArrowExpressionClause };
        }
Example #32
0
 public virtual BoundStatement InstrumentReturnStatement(BoundReturnStatement original, BoundStatement rewritten)
 {
     return rewritten;
 }
        private BoundStatement UnpendBranches(
            AwaitFinallyFrame frame,
            SynthesizedLocal pendingBranchVar,
            SynthesizedLocal pendingException)
        {
            var parent = frame.ParentOpt;

            // handle proxy labels if have any
            var proxiedLabels = frame.proxiedLabels;
            var proxyLabels = frame.proxyLabels;

            // skip 0 - it means we took no explicit branches
            int i = 1;
            var cases = ArrayBuilder<BoundSwitchSection>.GetInstance();

            if (proxiedLabels != null)
            {
                for (int cnt = proxiedLabels.Count; i <= cnt; i++)
                {
                    var target = proxiedLabels[i - 1];
                    var parentProxy = parent.ProxyLabelIfNeeded(target);
                    var caseStatement = _F.SwitchSection(i, _F.Goto(parentProxy));
                    cases.Add(caseStatement);
                }
            }

            if (frame.returnProxyLabel != null)
            {
                BoundLocal pendingValue = null;
                if (frame.returnValue != null)
                {
                    pendingValue = _F.Local(frame.returnValue);
                }

                SynthesizedLocal returnValue;
                BoundStatement unpendReturn;

                var returnLabel = parent.ProxyReturnIfNeeded(_F.CurrentMethod, pendingValue, out returnValue);

                if (returnLabel == null)
                {
                    unpendReturn = new BoundReturnStatement(_F.Syntax, pendingValue);
                }
                else
                {
                    if (pendingValue == null)
                    {
                        unpendReturn = _F.Goto(returnLabel);
                    }
                    else
                    {
                        unpendReturn = _F.Block(
                            _F.Assignment(
                                _F.Local(returnValue),
                                pendingValue),
                            _F.Goto(returnLabel));
                    }
                }

                var caseStatement = _F.SwitchSection(i, unpendReturn);
                cases.Add(caseStatement);
            }

            return _F.Switch(_F.Local(pendingBranchVar), cases.ToImmutableAndFree());
        }
        public override BoundNode VisitReturnStatement(BoundReturnStatement node)
        {
            SynthesizedLocal returnValue;
            var returnLabel = _currentAwaitFinallyFrame.ProxyReturnIfNeeded(
                _F.CurrentMethod,
                node.ExpressionOpt,
                out returnValue);

            if (returnLabel == null)
            {
                return base.VisitReturnStatement(node);
            }

            var returnExpr = (BoundExpression)(this.Visit(node.ExpressionOpt));
            if (returnExpr != null)
            {
                return _F.Block(
                        _F.Assignment(
                            _F.Local(returnValue),
                            returnExpr),
                        _F.Goto(
                            returnLabel));
            }
            else
            {
                return _F.Goto(returnLabel);
            }
        }
        private static bool ReturnsValueWithinExpressionBodiedConstruct(BoundReturnStatement returnStatement)
        {
            if (returnStatement.WasCompilerGenerated &&
                returnStatement.ExpressionOpt != null &&
                returnStatement.ExpressionOpt.Syntax != null)
            {
                SyntaxKind parentKind = returnStatement.ExpressionOpt.Syntax.Parent.Kind();
                switch (parentKind)
                {
                    case SyntaxKind.ParenthesizedLambdaExpression:
                    case SyntaxKind.SimpleLambdaExpression:
                    case SyntaxKind.ArrowExpressionClause:
                        return true;
                }
            }

            return false;
        }
            public override BoundNode VisitReturnStatement(BoundReturnStatement node)
            {
                if (node.ExpressionOpt != null)
                {
                    Debug.Assert(method.IsGenericTaskReturningAsync());
                    return F.Block(
                        F.Assignment(F.Local(exprRetValue), (BoundExpression)Visit(node.ExpressionOpt)),
                        F.Goto(exprReturnLabel));
                }

                return F.Goto(exprReturnLabel);
            }
        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);
        }
Example #38
0
        internal BoundBlock WrapExpressionLambdaBody(BoundExpression expression, CSharpSyntaxNode node, DiagnosticBag diagnostics)
        {
            var returnType = this.GetCurrentReturnType();
            BoundStatement statement;

            if ((object)returnType != null)
            {
                if (returnType.SpecialType == SpecialType.System_Void || IsTaskReturningAsyncMethod())
                {
                    // If the return type is void then the expression is required to be a legal
                    // statement expression.

                    bool errors = false;
                    if (!IsValidStatementExpression(node, expression))
                    {
                        Error(diagnostics, ErrorCode.ERR_IllegalStatement, node);
                        errors = true;
                    }
                    var expressionStatement = new BoundExpressionStatement(expression.Syntax, expression, errors);
                    CheckForUnobservedAwaitable(expressionStatement, diagnostics);
                    statement = expressionStatement;
                }
                else
                {
                    expression = CreateReturnConversion(node, diagnostics, expression, returnType);
                    statement = new BoundReturnStatement(expression.Syntax, expression) { WasCompilerGenerated = true };
                }
            }
            else if ((object)expression.Type != null && expression.Type.SpecialType == SpecialType.System_Void)
            {
                statement = new BoundExpressionStatement(expression.Syntax, expression) { WasCompilerGenerated = true };
            }
            else
            {
                statement = new BoundReturnStatement(expression.Syntax, expression) { WasCompilerGenerated = true };
            }

            // Need to attach the tree for when we generate sequence points.
            var block = new BoundBlock(node, ImmutableArray<LocalSymbol>.Empty, ImmutableArray.Create<BoundStatement>(statement)) { WasCompilerGenerated = true };
            return block;
        }
Example #39
0
        /// <summary>
        /// Generate a thread-safe accessor for a regular field-like event.
        ///
        /// DelegateType tmp0 = _event; //backing field
        /// DelegateType tmp1;
        /// DelegateType tmp2;
        /// do {
        ///     tmp1 = tmp0;
        ///     tmp2 = (DelegateType)Delegate.Combine(tmp1, value); //Remove for -=
        ///     tmp0 = Interlocked.CompareExchange&lt;DelegateType&gt;(ref _event, tmp2, tmp1);
        /// } while ((object)tmp0 != (object)tmp1);
        ///
        /// Note, if System.Threading.Interlocked.CompareExchange&lt;T&gt; is not available,
        /// we emit the following code and mark the method Synchronized (unless it is a struct).
        ///
        /// _event = (DelegateType)Delegate.Combine(_event, value); //Remove for -=
        ///
        /// </summary>
        internal static BoundBlock ConstructFieldLikeEventAccessorBody_Regular(SourceEventSymbol eventSymbol, bool isAddMethod, CSharpCompilation compilation, DiagnosticBag diagnostics)
        {
            CSharpSyntaxNode syntax = eventSymbol.CSharpSyntaxNode;

            TypeSymbol      delegateType  = eventSymbol.Type;
            MethodSymbol    accessor      = isAddMethod ? eventSymbol.AddMethod : eventSymbol.RemoveMethod;
            ParameterSymbol thisParameter = accessor.ThisParameter;

            TypeSymbol boolType = compilation.GetSpecialType(SpecialType.System_Boolean);

            SpecialMember updateMethodId = isAddMethod ? SpecialMember.System_Delegate__Combine : SpecialMember.System_Delegate__Remove;
            MethodSymbol  updateMethod   = (MethodSymbol)compilation.GetSpecialTypeMember(updateMethodId);

            BoundStatement @return = new BoundReturnStatement(syntax,
                                                              expressionOpt: null)
            {
                WasCompilerGenerated = true
            };

            if (updateMethod == null)
            {
                MemberDescriptor memberDescriptor = SpecialMembers.GetDescriptor(updateMethodId);
                diagnostics.Add(new CSDiagnostic(new CSDiagnosticInfo(ErrorCode.ERR_MissingPredefinedMember,
                                                                      memberDescriptor.DeclaringTypeMetadataName,
                                                                      memberDescriptor.Name),
                                                 syntax.Location));

                return(new BoundBlock(syntax,
                                      locals: ImmutableArray <LocalSymbol> .Empty,
                                      statements: ImmutableArray.Create <BoundStatement>(@return))
                {
                    WasCompilerGenerated = true
                });
            }

            Binder.ReportUseSiteDiagnostics(updateMethod, diagnostics, syntax);

            BoundThisReference fieldReceiver = eventSymbol.IsStatic ?
                                               null :
                                               new BoundThisReference(syntax, thisParameter.Type)
            {
                WasCompilerGenerated = true
            };

            BoundFieldAccess boundBackingField = new BoundFieldAccess(syntax,
                                                                      receiver: fieldReceiver,
                                                                      fieldSymbol: eventSymbol.AssociatedField,
                                                                      constantValueOpt: null)
            {
                WasCompilerGenerated = true
            };

            BoundParameter boundParameter = new BoundParameter(syntax,
                                                               parameterSymbol: accessor.Parameters[0])
            {
                WasCompilerGenerated = true
            };

            BoundExpression delegateUpdate;

            MethodSymbol compareExchangeMethod = (MethodSymbol)compilation.GetWellKnownTypeMember(WellKnownMember.System_Threading_Interlocked__CompareExchange_T);

            if ((object)compareExchangeMethod == null)
            {
                // (DelegateType)Delegate.Combine(_event, value)
                delegateUpdate = BoundConversion.SynthesizedNonUserDefined(syntax,
                                                                           operand: BoundCall.Synthesized(syntax,
                                                                                                          receiverOpt: null,
                                                                                                          method: updateMethod,
                                                                                                          arguments: ImmutableArray.Create <BoundExpression>(boundBackingField, boundParameter)),
                                                                           kind: ConversionKind.ExplicitReference,
                                                                           type: delegateType);

                // _event = (DelegateType)Delegate.Combine(_event, value);
                BoundStatement eventUpdate = new BoundExpressionStatement(syntax,
                                                                          expression: new BoundAssignmentOperator(syntax,
                                                                                                                  left: boundBackingField,
                                                                                                                  right: delegateUpdate,
                                                                                                                  type: delegateType)
                {
                    WasCompilerGenerated = true
                })
                {
                    WasCompilerGenerated = true
                };

                return(new BoundBlock(syntax,
                                      locals: ImmutableArray <LocalSymbol> .Empty,
                                      statements: ImmutableArray.Create <BoundStatement>(
                                          eventUpdate,
                                          @return))
                {
                    WasCompilerGenerated = true
                });
            }

            compareExchangeMethod = compareExchangeMethod.Construct(ImmutableArray.Create <TypeSymbol>(delegateType));

            Binder.ReportUseSiteDiagnostics(compareExchangeMethod, diagnostics, syntax);

            GeneratedLabelSymbol loopLabel = new GeneratedLabelSymbol("loop");

            const int numTemps = 3;

            LocalSymbol[] tmps      = new LocalSymbol[numTemps];
            BoundLocal[]  boundTmps = new BoundLocal[numTemps];

            for (int i = 0; i < numTemps; i++)
            {
                tmps[i]      = new SynthesizedLocal(accessor, delegateType, SynthesizedLocalKind.LoweringTemp);
                boundTmps[i] = new BoundLocal(syntax, tmps[i], null, delegateType);
            }

            // tmp0 = _event;
            BoundStatement tmp0Init = new BoundExpressionStatement(syntax,
                                                                   expression: new BoundAssignmentOperator(syntax,
                                                                                                           left: boundTmps[0],
                                                                                                           right: boundBackingField,
                                                                                                           type: delegateType)
            {
                WasCompilerGenerated = true
            })
            {
                WasCompilerGenerated = true
            };

            // LOOP:
            BoundStatement loopStart = new BoundLabelStatement(syntax,
                                                               label: loopLabel)
            {
                WasCompilerGenerated = true
            };

            // tmp1 = tmp0;
            BoundStatement tmp1Update = new BoundExpressionStatement(syntax,
                                                                     expression: new BoundAssignmentOperator(syntax,
                                                                                                             left: boundTmps[1],
                                                                                                             right: boundTmps[0],
                                                                                                             type: delegateType)
            {
                WasCompilerGenerated = true
            })
            {
                WasCompilerGenerated = true
            };

            // (DelegateType)Delegate.Combine(tmp1, value)
            delegateUpdate = BoundConversion.SynthesizedNonUserDefined(syntax,
                                                                       operand: BoundCall.Synthesized(syntax,
                                                                                                      receiverOpt: null,
                                                                                                      method: updateMethod,
                                                                                                      arguments: ImmutableArray.Create <BoundExpression>(boundTmps[1], boundParameter)),
                                                                       kind: ConversionKind.ExplicitReference,
                                                                       type: delegateType);

            // tmp2 = (DelegateType)Delegate.Combine(tmp1, value);
            BoundStatement tmp2Update = new BoundExpressionStatement(syntax,
                                                                     expression: new BoundAssignmentOperator(syntax,
                                                                                                             left: boundTmps[2],
                                                                                                             right: delegateUpdate,
                                                                                                             type: delegateType)
            {
                WasCompilerGenerated = true
            })
            {
                WasCompilerGenerated = true
            };

            // Interlocked.CompareExchange<DelegateType>(ref _event, tmp2, tmp1)
            BoundExpression compareExchange = BoundCall.Synthesized(syntax,
                                                                    receiverOpt: null,
                                                                    method: compareExchangeMethod,
                                                                    arguments: ImmutableArray.Create <BoundExpression>(boundBackingField, boundTmps[2], boundTmps[1]));

            // tmp0 = Interlocked.CompareExchange<DelegateType>(ref _event, tmp2, tmp1);
            BoundStatement tmp0Update = new BoundExpressionStatement(syntax,
                                                                     expression: new BoundAssignmentOperator(syntax,
                                                                                                             left: boundTmps[0],
                                                                                                             right: compareExchange,
                                                                                                             type: delegateType)
            {
                WasCompilerGenerated = true
            })
            {
                WasCompilerGenerated = true
            };

            // tmp0 == tmp1 // i.e. exit when they are equal, jump to start otherwise
            BoundExpression loopExitCondition = new BoundBinaryOperator(syntax,
                                                                        operatorKind: BinaryOperatorKind.ObjectEqual,
                                                                        left: boundTmps[0],
                                                                        right: boundTmps[1],
                                                                        constantValueOpt: null,
                                                                        methodOpt: null,
                                                                        resultKind: LookupResultKind.Viable,
                                                                        type: boolType)
            {
                WasCompilerGenerated = true
            };

            // branchfalse (tmp0 == tmp1) LOOP
            BoundStatement loopEnd = new BoundConditionalGoto(syntax,
                                                              condition: loopExitCondition,
                                                              jumpIfTrue: false,
                                                              label: loopLabel)
            {
                WasCompilerGenerated = true
            };

            return(new BoundBlock(syntax,
                                  locals: tmps.AsImmutable(),
                                  statements: ImmutableArray.Create <BoundStatement>(
                                      tmp0Init,
                                      loopStart,
                                      tmp1Update,
                                      tmp2Update,
                                      tmp0Update,
                                      loopEnd,
                                      @return))
            {
                WasCompilerGenerated = true
            });
        }
Example #40
0
        public override BoundStatement InstrumentReturnStatement(BoundReturnStatement original, BoundStatement rewritten)
        {
            rewritten = base.InstrumentReturnStatement(original, rewritten);

            if (original.WasCompilerGenerated && original.ExpressionOpt == null && original.Syntax.Kind() == SyntaxKind.Block)
            {
                // implicit return added by the compiler
                return new BoundSequencePointWithSpan(original.Syntax, rewritten, ((BlockSyntax)original.Syntax).CloseBraceToken.Span);
            }

            return new BoundSequencePoint(original.Syntax, rewritten);
        }
Example #41
0
 public override BoundStatement InstrumentReturnStatement(BoundReturnStatement original, BoundStatement rewritten)
 {
     return(Previous.InstrumentReturnStatement(original, rewritten));
 }
Example #42
0
 public virtual BoundStatement InstrumentReturnStatement(BoundReturnStatement original, BoundStatement rewritten)
 {
     return(rewritten);
 }