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()); }
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; }
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()); }
// 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); } } }
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; }
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; }