예제 #1
0
        protected BoundStatement Rewrite()
        {
            if (this.body.HasErrors)
            {
                return(this.body);
            }

            F.OpenNestedType(stateMachineType);

            GenerateControlFields();

            // fields for the initial values of all the parameters of the method
            if (PreserveInitialParameterValues)
            {
                initialParameters = new Dictionary <Symbol, CapturedSymbolReplacement>();
            }

            // fields for the captured variables of the method
            var variablesCaptured = IteratorAndAsyncCaptureWalker.Analyze(compilationState.ModuleBuilderOpt.Compilation, method, body);

            this.nonReusableLocalProxies = CreateNonReusableLocalProxies(variablesCaptured);
            this.variablesCaptured       = variablesCaptured;

            GenerateMethodImplementations();

            // Return a replacement body for the original method
            return(ReplaceOriginalMethod());
        }
예제 #2
0
        protected BoundStatement Rewrite()
        {
            if (this.body.HasErrors)
            {
                return(this.body);
            }

            F.OpenNestedType(stateMachineType);

            GenerateControlFields();

            // fields for the initial values of all the parameters of the method
            if (PreserveInitialParameterValues)
            {
                initialParameters = new Dictionary <Symbol, CapturedSymbolReplacement>();
            }

            // fields for the captured variables of the method
            var variablesToHoist = IteratorAndAsyncCaptureWalker.Analyze(F.Compilation, method, body, diagnostics);

            CreateNonReusableLocalProxies(variablesToHoist, out this.nonReusableLocalProxies, out this.nextFreeHoistedLocalSlot);

            this.hoistedVariables = variablesToHoist;

            GenerateMethodImplementations();

            // Return a replacement body for the kickoff method
            return(GenerateKickoffMethodBody());
        }
        public static MultiDictionary<Symbol, CSharpSyntaxNode> Analyze(CSharpCompilation compilation, MethodSymbol method, BoundNode node)
        {
            var emptyStructs = new CaptureWalkerEmptyStructTypeCache();
            var initiallyAssignedVariables = UnassignedVariablesWalker.Analyze(compilation, method, node, emptyStructs);

            var walker = new IteratorAndAsyncCaptureWalker(compilation, method, node, emptyStructs, initiallyAssignedVariables);

            bool badRegion = false;
            walker.Analyze(ref badRegion);
            Debug.Assert(!badRegion);

            var result = walker.variablesCaptured;


            if (!method.IsStatic && method.ContainingType.TypeKind == TypeKind.Struct)
            {
                // It is possible that the enclosing method only *writes* to the enclosing struct, but in that
                // case it should be considered captured anyway so that we have a proxy for it to write to.
                result.Add(method.ThisParameter, node.Syntax);
            }

            foreach (var variable in result.Keys.ToArray()) // take a snapshot, as we are modifying the underlying multidictionary
            {
                var local = variable as LocalSymbol;
                if ((object)local != null && local.RefKind != RefKind.None)
                {
                    walker.AddSpillsForRef(walker.refLocalInitializers[local], result[local]);
                }
            }

            walker.Free();
            return result;
        }
        public static MultiDictionary <Symbol, CSharpSyntaxNode> Analyze(CSharpCompilation compilation, MethodSymbol method, BoundNode node)
        {
            IteratorAndAsyncCaptureWalker w = new IteratorAndAsyncCaptureWalker(compilation, method, node);
            bool badRegion = false;

            w.Analyze(ref badRegion);
            Debug.Assert(!badRegion);
            var result = w.variablesCaptured;

            if (!method.IsStatic && method.ContainingType.TypeKind == TypeKind.Struct)
            {
                // It is possible that the enclosing method only *writes* to the enclosing struct, but in that
                // case it should be considered captured anyway so that we have a proxy for it to write to.
                w.variablesCaptured.Add(method.ThisParameter, node.Syntax);
            }
            foreach (var variable in result.Keys.ToArray()) // take a snapshot, as we are modifying the underlying multidictionary
            {
                var local = variable as LocalSymbol;
                if ((object)local == null || local.RefKind == RefKind.None)
                {
                    continue;
                }
                w.AddSpillsForRef(w.refLocalInitializers[local], result[local]);
            }
            w.Free();
            return(result);
        }
 public OutsideVariablesUsedInside(IteratorAndAsyncCaptureWalker analyzer, MethodSymbol topLevelMethod, IteratorAndAsyncCaptureWalker parent)
     : base(parent._recursionDepth)
 {
     _analyzer       = analyzer;
     _topLevelMethod = topLevelMethod;
     _localsInScope  = new HashSet <Symbol>();
     _parent         = parent;
 }
예제 #6
0
        protected BoundStatement Rewrite()
        {
            if (this.body.HasErrors)
            {
                return(this.body);
            }

            F.OpenNestedType(stateMachineType);

            GenerateControlFields();

            if (PreserveInitialParameterValuesAndThreadId && CanGetThreadId())
            {
                // if it is an enumerable or async-enumerable, and either Environment.CurrentManagedThreadId or Thread.ManagedThreadId are available
                // add a field: int initialThreadId
                initialThreadIdField = F.StateMachineField(
                    F.SpecialType(SpecialType.System_Int32),
                    GeneratedNames.MakeIteratorCurrentThreadIdFieldName()
                    );
            }

            // fields for the initial values of all the parameters of the method
            if (PreserveInitialParameterValuesAndThreadId)
            {
                initialParameters = new Dictionary <Symbol, CapturedSymbolReplacement>();
            }

            // fields for the captured variables of the method
            var variablesToHoist = IteratorAndAsyncCaptureWalker.Analyze(
                F.Compilation,
                method,
                body,
                diagnostics.DiagnosticBag
                );

            if (diagnostics.HasAnyErrors())
            {
                // Avoid triggering assertions in further lowering.
                return(new BoundBadStatement(
                           F.Syntax,
                           ImmutableArray <BoundNode> .Empty,
                           hasErrors: true
                           ));
            }

            CreateNonReusableLocalProxies(
                variablesToHoist,
                out this.nonReusableLocalProxies,
                out this.nextFreeHoistedLocalSlot
                );

            this.hoistedVariables = variablesToHoist;

            GenerateMethodImplementations();

            // Return a replacement body for the kickoff method
            return(GenerateKickoffMethodBody());
        }
예제 #7
0
        // Returns deterministically ordered list of variables that ought to be hoisted.
        public static OrderedSet <Symbol> Analyze(CSharpCompilation compilation, MethodSymbol method, BoundNode node, DiagnosticBag diagnostics)
        {
            var initiallyAssignedVariables = UnassignedVariablesWalker.Analyze(compilation, method, node, convertInsufficientExecutionStackExceptionToCancelledByStackGuardException: true);
            var walker = new IteratorAndAsyncCaptureWalker(compilation, method, node, new NeverEmptyStructTypeCache(), initiallyAssignedVariables);

            walker._convertInsufficientExecutionStackExceptionToCancelledByStackGuardException = true;

            bool badRegion = false;

            walker.Analyze(ref badRegion);
            Debug.Assert(!badRegion);

            if (!method.IsStatic && method.ContainingType.TypeKind == TypeKind.Struct)
            {
                // It is possible that the enclosing method only *writes* to the enclosing struct, but in that
                // case it should be considered captured anyway so that we have a proxy for it to write to.
                walker.CaptureVariable(method.ThisParameter, node.Syntax);
            }

            var variablesToHoist       = walker._variablesToHoist;
            var lazyDisallowedCaptures = walker._lazyDisallowedCaptures;
            var allVariables           = walker.variableBySlot;

            walker.Free();

            if (lazyDisallowedCaptures != null)
            {
                foreach (var kvp in lazyDisallowedCaptures)
                {
                    var variable = kvp.Key;
                    var type     = (variable.Kind == SymbolKind.Local) ? ((LocalSymbol)variable).Type : ((ParameterSymbol)variable).Type;

                    foreach (CSharpSyntaxNode syntax in kvp.Value)
                    {
                        // CS4013: Instance of type '{0}' cannot be used inside an anonymous function, query expression, iterator block or async method
                        diagnostics.Add(ErrorCode.ERR_SpecialByRefInLambda, syntax.Location, type);
                    }
                }
            }

            if (compilation.Options.OptimizationLevel != OptimizationLevel.Release)
            {
                Debug.Assert(variablesToHoist.Count == 0);

                // In debug build we hoist all locals and parameters:
                foreach (var v in allVariables)
                {
                    var symbol = v.Symbol;
                    if ((object)symbol != null && HoistInDebugBuild(symbol))
                    {
                        variablesToHoist.Add(symbol);
                    }
                }
            }

            return(variablesToHoist);
        }
        // Returns deterministically ordered list of variables that ought to be hoisted.
        public static OrderedSet<Symbol> Analyze(CSharpCompilation compilation, MethodSymbol method, BoundNode node, DiagnosticBag diagnostics)
        {
            var initiallyAssignedVariables = UnassignedVariablesWalker.Analyze(compilation, method, node, convertInsufficientExecutionStackExceptionToCancelledByStackGuardException: true);
            var walker = new IteratorAndAsyncCaptureWalker(compilation, method, node, new NeverEmptyStructTypeCache(), initiallyAssignedVariables);

            walker._convertInsufficientExecutionStackExceptionToCancelledByStackGuardException = true;

            bool badRegion = false;
            walker.Analyze(ref badRegion);
            Debug.Assert(!badRegion);

            if (!method.IsStatic && method.ContainingType.TypeKind == TypeKind.Struct)
            {
                // It is possible that the enclosing method only *writes* to the enclosing struct, but in that
                // case it should be considered captured anyway so that we have a proxy for it to write to.
                walker.CaptureVariable(method.ThisParameter, node.Syntax);
            }

            var variablesToHoist = walker._variablesToHoist;
            var lazyDisallowedCaptures = walker._lazyDisallowedCaptures;
            var allVariables = walker.variableBySlot;

            walker.Free();

            if (lazyDisallowedCaptures != null)
            {
                foreach (var kvp in lazyDisallowedCaptures)
                {
                    var variable = kvp.Key;
                    var type = (variable.Kind == SymbolKind.Local) ? ((LocalSymbol)variable).Type : ((ParameterSymbol)variable).Type;

                    foreach (CSharpSyntaxNode syntax in kvp.Value)
                    {
                        // CS4013: Instance of type '{0}' cannot be used inside an anonymous function, query expression, iterator block or async method
                        diagnostics.Add(ErrorCode.ERR_SpecialByRefInLambda, syntax.Location, type);
                    }
                }
            }

            if (compilation.Options.OptimizationLevel != OptimizationLevel.Release)
            {
                Debug.Assert(variablesToHoist.Count == 0);

                // In debug build we hoist all locals and parameters:
                variablesToHoist.AddRange(from v in allVariables
                                          where v.Symbol != null && HoistInDebugBuild(v.Symbol)
                                          select v.Symbol);
            }

            return variablesToHoist;
        }
        // Returns deterministically ordered list of variables that ought to be hoisted.
        public static OrderedSet <Symbol> Analyze(CSharpCompilation compilation, MethodSymbol method, BoundNode node, DiagnosticBag diagnostics)
        {
            var initiallyAssignedVariables = UnassignedVariablesWalker.Analyze(compilation, method, node, convertInsufficientExecutionStackExceptionToCancelledByStackGuardException: true);
            var walker = new IteratorAndAsyncCaptureWalker(compilation, method, node, initiallyAssignedVariables);

            walker._convertInsufficientExecutionStackExceptionToCancelledByStackGuardException = true;

            bool badRegion = false;

            walker.Analyze(ref badRegion);
            Debug.Assert(!badRegion);

            if (!method.IsStatic && method.ContainingType.TypeKind == TypeKind.Struct)
            {
                // It is possible that the enclosing method only *writes* to the enclosing struct, but in that
                // case it should be considered captured anyway so that we have a proxy for it to write to.
                walker.CaptureVariable(method.ThisParameter, node.Syntax);
            }

            var variablesToHoist       = walker._variablesToHoist;
            var lazyDisallowedCaptures = walker._lazyDisallowedCaptures;
            var allVariables           = walker.variableBySlot;

            walker.Free();

            if (lazyDisallowedCaptures != null)
            {
                foreach (var kvp in lazyDisallowedCaptures)
                {
                    var variable = kvp.Key;
                    var type     = (variable.Kind == SymbolKind.Local) ? ((LocalSymbol)variable).Type : ((ParameterSymbol)variable).Type;

                    if (variable is SynthesizedLocal local && local.SynthesizedKind == SynthesizedLocalKind.Spill)
                    {
                        Debug.Assert(local.TypeWithAnnotations.IsRestrictedType());
                        diagnostics.Add(ErrorCode.ERR_ByRefTypeAndAwait, local.Locations[0], local.TypeWithAnnotations);
                    }
                    else
                    {
                        foreach (CSharpSyntaxNode syntax in kvp.Value)
                        {
                            // CS4013: Instance of type '{0}' cannot be used inside an anonymous function, query expression, iterator block or async method
                            diagnostics.Add(ErrorCode.ERR_SpecialByRefInLambda, syntax.Location, type);
                        }
                    }
                }
예제 #10
0
        protected BoundStatement Rewrite()
        {
            if (this.body.HasErrors)
            {
                return(this.body);
            }

            TypeMap TypeMap = stateMachineClass.TypeMap;

            F.OpenNestedType(stateMachineClass);
            F.CompilationState.StateMachineImplementationClass[method] = stateMachineClass;

            // Add a field: int _state
            var intType = F.SpecialType(SpecialType.System_Int32);

            stateField = F.SynthesizeField(intType, GeneratedNames.MakeStateMachineStateName(), isPublic: IsStateFieldPublic);

            GenerateFields();

            // and fields for the initial values of all the parameters of the method
            if (PreserveInitialLocals)
            {
                initialParameters = new Dictionary <Symbol, CapturedSymbolReplacement>();
            }

            // add fields for the captured variables of the method
            var dictionary = IteratorAndAsyncCaptureWalker.Analyze(compilationState.ModuleBuilder.Compilation, method, body);
            IOrderedEnumerable <Symbol> captured =
                from local in dictionary.Keys
                orderby local.Name, local.Locations.Length == 0 ? 0 : local.Locations[0].SourceSpan.Start
            select local;

            this.variablesCaptured = new HashSet <Symbol>(captured);
            this.variableProxies   = new Dictionary <Symbol, CapturedSymbolReplacement>();

            CreateInitialProxies(TypeMap, captured, dictionary);
            GenerateMethodImplementations();

            // Return a replacement body for the original method
            return(ReplaceOriginalMethod());
        }
        public static MultiDictionary <Symbol, CSharpSyntaxNode> Analyze(CSharpCompilation compilation, MethodSymbol method, BoundNode node)
        {
            var  initiallyAssignedVariables = UnassignedVariablesWalker.Analyze(compilation, method, node);
            var  walker    = new IteratorAndAsyncCaptureWalker(compilation, method, node, new NeverEmptyStructTypeCache(), initiallyAssignedVariables);
            bool badRegion = false;

            walker.Analyze(ref badRegion);
            Debug.Assert(!badRegion);

            var result = walker.variablesCaptured;

            if (!method.IsStatic && method.ContainingType.TypeKind == TypeKind.Struct)
            {
                // It is possible that the enclosing method only *writes* to the enclosing struct, but in that
                // case it should be considered captured anyway so that we have a proxy for it to write to.
                result.Add(method.ThisParameter, node.Syntax);
            }

            walker.Free();
            return(result);
        }
        public static MultiDictionary<Symbol, CSharpSyntaxNode> Analyze(CSharpCompilation compilation, MethodSymbol method, BoundNode node)
        {
            var emptyStructs = new CaptureWalkerEmptyStructTypeCache();
            var initiallyAssignedVariables = UnassignedVariablesWalker.Analyze(compilation, method, node, emptyStructs);

            var walker = new IteratorAndAsyncCaptureWalker(compilation, method, node, emptyStructs, initiallyAssignedVariables);

            bool badRegion = false;
            walker.Analyze(ref badRegion);
            Debug.Assert(!badRegion);

            var result = walker.variablesCaptured;

            if (!method.IsStatic && method.ContainingType.TypeKind == TypeKind.Struct)
            {
                // It is possible that the enclosing method only *writes* to the enclosing struct, but in that
                // case it should be considered captured anyway so that we have a proxy for it to write to.
                result.Add(method.ThisParameter, node.Syntax);
            }

            walker.Free();
            return result;
        }
예제 #13
0
        protected BoundStatement Rewrite()
        {
            if (this.body.HasErrors)
            {
                return(this.body);
            }

            F.OpenNestedType(stateMachineClass);

            // Add a field: int _state
            var intType = F.SpecialType(SpecialType.System_Int32);

            stateField = F.StateMachineField(intType, GeneratedNames.MakeStateMachineStateName(), IsStateFieldPublic);

            GenerateFields();

            // and fields for the initial values of all the parameters of the method
            if (PreserveInitialParameterValues)
            {
                initialParameters = new Dictionary <Symbol, CapturedSymbolReplacement>();
            }

            // add fields for the captured variables of the method
            var captured = IteratorAndAsyncCaptureWalker.Analyze(compilationState.ModuleBuilderOpt.Compilation, method, body);

            this.variablesCaptured = new HashSet <Symbol>(captured.Keys);

            this.variableProxies = new Dictionary <Symbol, CapturedSymbolReplacement>();

            CreateInitialProxies(captured);

            GenerateMethodImplementations();

            // Return a replacement body for the original method
            return(ReplaceOriginalMethod());
        }
 public OutsideVariablesUsedInside(IteratorAndAsyncCaptureWalker analyzer, MethodSymbol topLevelMethod)
 {
     _analyzer       = analyzer;
     _topLevelMethod = topLevelMethod;
     _localsInScope  = new HashSet <Symbol>();
 }
 public OutsideVariablesUsedInside(IteratorAndAsyncCaptureWalker analyzer, MethodSymbol topLevelMethod)
 {
     _analyzer = analyzer;
     _topLevelMethod = topLevelMethod;
     _localsInScope = new HashSet<Symbol>();
 }
 public OutsideVariablesUsedInside(IteratorAndAsyncCaptureWalker analyzer, MethodSymbol topLevelMethod, IteratorAndAsyncCaptureWalker parent)
     : base(parent._recursionDepth)
 {
     _analyzer = analyzer;
     _topLevelMethod = topLevelMethod;
     _localsInScope = new HashSet<Symbol>();
     _parent = parent;
 }