private static string MakeName(VariableSlotAllocator slotAllocatorOpt, SyntaxNode scopeSyntaxOpt, MethodDebugId methodId, int closureOrdinal) { if (scopeSyntaxOpt == null) { // Display class is shared among static non-generic lambdas accross generations, method ordinal is -1 in that case. // A new display class of a static generic lambda is created for each method and each generation. return(GeneratedNames.MakeStaticLambdaDisplayClassName(methodId.Ordinal, methodId.Generation)); } int previousClosureOrdinal; if (slotAllocatorOpt != null && slotAllocatorOpt.TryGetPreviousClosure(scopeSyntaxOpt, out previousClosureOrdinal)) { methodId = slotAllocatorOpt.PreviousMethodId; closureOrdinal = previousClosureOrdinal; } // If we haven't found existing closure in the previous generation, use the current generation method ordinal. // That is, don't try to reuse previous generation method ordinal as that might create name conflict. // E.g. // Gen0 Gen1 // F() { new closure } // ordinal 0 // G() { } // ordinal 0 G() { new closure } // ordinal 1 // // In the example above G is updated and F is added. // G's ordinal in Gen0 is 0. If we used that ordinal for updated G's new closure it would conflict with F's ordinal. Debug.Assert(methodId.Ordinal >= 0); return(GeneratedNames.MakeLambdaDisplayClassName(methodId.Ordinal, methodId.Generation, closureOrdinal)); }
internal AsyncIteratorRewriter( BoundStatement body, MethodSymbol method, int methodOrdinal, AsyncStateMachine stateMachineType, VariableSlotAllocator slotAllocatorOpt, TypeCompilationState compilationState, BindingDiagnosticBag diagnostics ) : base( body, method, methodOrdinal, stateMachineType, slotAllocatorOpt, compilationState, diagnostics ) { Debug.Assert( !TypeSymbol.Equals( method.IteratorElementTypeWithAnnotations.Type, null, TypeCompareKind.ConsiderEverything2 ) ); _isEnumerable = method.IsAsyncReturningIAsyncEnumerable( method.DeclaringCompilation ); Debug.Assert( _isEnumerable != method.IsAsyncReturningIAsyncEnumerator(method.DeclaringCompilation) ); }
internal AsyncMethodToStateMachineRewriter( MethodSymbol method, int methodOrdinal, AsyncMethodBuilderMemberCollection asyncMethodBuilderMemberCollection, SyntheticBoundNodeFactory F, FieldSymbol state, FieldSymbol builder, IReadOnlySet <Symbol> hoistedVariables, IReadOnlyDictionary <Symbol, CapturedSymbolReplacement> nonReusableLocalProxies, SynthesizedLocalOrdinalsDispenser synthesizedLocalOrdinals, ArrayBuilder <StateMachineStateDebugInfo> stateMachineStateDebugInfoBuilder, VariableSlotAllocator slotAllocatorOpt, int nextFreeHoistedLocalSlot, BindingDiagnosticBag diagnostics) : base(F, method, state, hoistedVariables, nonReusableLocalProxies, synthesizedLocalOrdinals, stateMachineStateDebugInfoBuilder, slotAllocatorOpt, nextFreeHoistedLocalSlot, diagnostics) { _method = method; _asyncMethodBuilderMemberCollection = asyncMethodBuilderMemberCollection; _asyncMethodBuilderField = builder; _exprReturnLabel = F.GenerateLabel("exprReturn"); _exitLabel = F.GenerateLabel("exitLabel"); _exprRetValue = method.IsAsyncEffectivelyReturningGenericTask(F.Compilation) ? F.SynthesizedLocal(asyncMethodBuilderMemberCollection.ResultType, syntax: F.Syntax, kind: SynthesizedLocalKind.AsyncMethodReturnValue) : null; _dynamicFactory = new LoweredDynamicOperationFactory(F, methodOrdinal); _awaiterFields = new Dictionary <TypeSymbol, FieldSymbol>(Symbols.SymbolEqualityComparer.IgnoringDynamicTupleNamesAndNullability); _nextAwaiterId = slotAllocatorOpt?.PreviousAwaiterSlotCount ?? 0; _placeholderMap = new Dictionary <BoundValuePlaceholderBase, BoundExpression>(); }
internal readonly TypeSymbol IteratorElementType; // only for async-iterators public AsyncStateMachine(VariableSlotAllocator variableAllocatorOpt, TypeCompilationState compilationState, MethodSymbol asyncMethod, int asyncMethodOrdinal, TypeKind typeKind) : base(variableAllocatorOpt, compilationState, asyncMethod, asyncMethodOrdinal) { _typeKind = typeKind; CSharpCompilation compilation = asyncMethod.DeclaringCompilation; var interfaces = ArrayBuilder <NamedTypeSymbol> .GetInstance(); if (asyncMethod.IsIterator) { var elementType = TypeMap.SubstituteType(asyncMethod.IteratorElementType).TypeSymbol; this.IteratorElementType = elementType; // IAsyncEnumerable<TResult> interfaces.Add(compilation.GetWellKnownType(WellKnownType.System_Collections_Generic_IAsyncEnumerable_T).Construct(elementType)); // IAsyncEnumerator<TResult> interfaces.Add(compilation.GetWellKnownType(WellKnownType.System_Collections_Generic_IAsyncEnumerator_T).Construct(elementType)); // IValueTaskSource<bool> interfaces.Add(compilation.GetWellKnownType(WellKnownType.System_Threading_Tasks_Sources_IValueTaskSource_T).Construct(compilation.GetSpecialType(SpecialType.System_Boolean))); // IStrongBox<ManualResetValueTaskSourceLogic<bool>> interfaces.Add(compilation.GetWellKnownType(WellKnownType.System_Runtime_CompilerServices_IStrongBox_T).Construct( compilation.GetWellKnownType(WellKnownType.System_Threading_Tasks_ManualResetValueTaskSourceLogic_T) .Construct(compilation.GetSpecialType(SpecialType.System_Boolean)))); // IAsyncDisposable interfaces.Add(compilation.GetWellKnownType(WellKnownType.System_IAsyncDisposable)); } interfaces.Add(compilation.GetWellKnownType(WellKnownType.System_Runtime_CompilerServices_IAsyncStateMachine)); _interfaces = interfaces.ToImmutableAndFree(); _constructor = new AsyncConstructor(this); }
public static Analysis Analyze( BoundNode node, MethodSymbol method, int topLevelMethodOrdinal, MethodSymbol substitutedSourceMethod, VariableSlotAllocator slotAllocatorOpt, TypeCompilationState compilationState, ArrayBuilder <ClosureDebugInfo> closureDebugInfo, DiagnosticBag diagnostics) { var methodsConvertedToDelegates = PooledHashSet <MethodSymbol> .GetInstance(); var scopeTree = ScopeTreeBuilder.Build( node, method, methodsConvertedToDelegates, diagnostics); Debug.Assert(scopeTree != null); var analysis = new Analysis( scopeTree, methodsConvertedToDelegates, method, topLevelMethodOrdinal, substitutedSourceMethod, slotAllocatorOpt, compilationState); analysis.MakeAndAssignEnvironments(); analysis.ComputeLambdaScopesAndFrameCaptures(method.ThisParameter); analysis.InlineThisOnlyEnvironments(); return(analysis); }
internal IteratorMethodToStateMachineRewriter( SyntheticBoundNodeFactory F, MethodSymbol originalMethod, FieldSymbol state, FieldSymbol current, IReadOnlySet <Symbol> hoistedVariables, IReadOnlyDictionary <Symbol, CapturedSymbolReplacement> nonReusableLocalProxies, SynthesizedLocalOrdinalsDispenser synthesizedLocalOrdinals, VariableSlotAllocator slotAllocatorOpt, int nextFreeHoistedLocalSlot, BindingDiagnosticBag diagnostics ) : base( F, originalMethod, state, hoistedVariables, nonReusableLocalProxies, synthesizedLocalOrdinals, slotAllocatorOpt, nextFreeHoistedLocalSlot, diagnostics, useFinalizerBookkeeping: false ) { _current = current; }
protected StateMachineRewriter( BoundStatement body, MethodSymbol method, SynthesizedContainer stateMachineType, VariableSlotAllocator slotAllocatorOpt, TypeCompilationState compilationState, DiagnosticBag diagnostics) { Debug.Assert(body != null); Debug.Assert(method != null); Debug.Assert((object)stateMachineType != null); Debug.Assert(compilationState != null); Debug.Assert(diagnostics != null); this.body = body; this.method = method; this.stateMachineType = stateMachineType; this.slotAllocatorOpt = slotAllocatorOpt; this.synthesizedLocalOrdinals = new SynthesizedLocalOrdinalsDispenser(); this.diagnostics = diagnostics; this.F = new SyntheticBoundNodeFactory(method, body.Syntax, compilationState, diagnostics); Debug.Assert(TypeSymbol.Equals(F.CurrentType, method.ContainingType, TypeCompareKind.ConsiderEverything2)); Debug.Assert(F.Syntax == body.Syntax); }
protected StateMachineRewriter( BoundStatement body, MethodSymbol method, SynthesizedContainer stateMachineType, VariableSlotAllocator slotAllocatorOpt, TypeCompilationState compilationState, DiagnosticBag diagnostics) { Debug.Assert(body != null); Debug.Assert(method != null); Debug.Assert(stateMachineType != null); Debug.Assert(compilationState != null); Debug.Assert(diagnostics != null); this.body = body; this.method = method; this.stateMachineType = stateMachineType; this.slotAllocatorOpt = slotAllocatorOpt; this.compilationState = compilationState; this.diagnostics = diagnostics; this.F = new SyntheticBoundNodeFactory(method, body.Syntax, compilationState, diagnostics); Debug.Assert(F.CurrentClass == method.ContainingType); Debug.Assert(F.Syntax == body.Syntax); }
internal AsyncMethodToStateMachineRewriter( MethodSymbol method, int methodOrdinal, AsyncMethodBuilderMemberCollection asyncMethodBuilderMemberCollection, SyntheticBoundNodeFactory F, FieldSymbol state, FieldSymbol builder, IReadOnlySet <Symbol> hoistedVariables, IReadOnlyDictionary <Symbol, CapturedSymbolReplacement> nonReusableLocalProxies, SynthesizedLocalOrdinalsDispenser synthesizedLocalOrdinals, VariableSlotAllocator slotAllocatorOpt, int nextFreeHoistedLocalSlot, DiagnosticBag diagnostics) : base(F, method, state, hoistedVariables, nonReusableLocalProxies, synthesizedLocalOrdinals, slotAllocatorOpt, nextFreeHoistedLocalSlot, diagnostics, useFinalizerBookkeeping: false) { _method = method; _asyncMethodBuilderMemberCollection = asyncMethodBuilderMemberCollection; _asyncMethodBuilderField = builder; _exprReturnLabel = F.GenerateLabel("exprReturn"); _exitLabel = F.GenerateLabel("exitLabel"); _exprRetValue = method.IsGenericTaskReturningAsync(F.Compilation) ? F.SynthesizedLocal(asyncMethodBuilderMemberCollection.ResultType, syntax: F.Syntax, kind: SynthesizedLocalKind.AsyncMethodReturnValue) : null; _dynamicFactory = new LoweredDynamicOperationFactory(F, methodOrdinal); _awaiterFields = new Dictionary <TypeSymbol, FieldSymbol>(TypeSymbol.EqualsIgnoringDynamicAndTupleNamesComparer); _nextAwaiterId = slotAllocatorOpt?.PreviousAwaiterSlotCount ?? 0; }
internal AsyncIteratorMethodToStateMachineRewriter(MethodSymbol method, int methodOrdinal, AsyncMethodBuilderMemberCollection asyncMethodBuilderMemberCollection, AsyncIteratorInfo asyncIteratorInfo, SyntheticBoundNodeFactory F, FieldSymbol state, FieldSymbol builder, IReadOnlySet <Symbol> hoistedVariables, IReadOnlyDictionary <Symbol, CapturedSymbolReplacement> nonReusableLocalProxies, SynthesizedLocalOrdinalsDispenser synthesizedLocalOrdinals, ArrayBuilder <StateMachineStateDebugInfo> stateMachineStateDebugInfoBuilder, VariableSlotAllocator slotAllocatorOpt, int nextFreeHoistedLocalSlot, BindingDiagnosticBag diagnostics) : base(method, methodOrdinal, asyncMethodBuilderMemberCollection, F, state, builder, hoistedVariables, nonReusableLocalProxies, synthesizedLocalOrdinals, stateMachineStateDebugInfoBuilder, slotAllocatorOpt, nextFreeHoistedLocalSlot, diagnostics) { Debug.Assert(asyncIteratorInfo != null); _asyncIteratorInfo = asyncIteratorInfo; _currentDisposalLabel = _exprReturnLabel; _exprReturnLabelTrue = F.GenerateLabel("yieldReturn"); _iteratorStateAllocator = new ResumableStateMachineStateAllocator( slotAllocatorOpt, firstState: StateMachineStates.FirstResumableAsyncIteratorState, increasing: false); }
/// <summary> /// Rewrite an async method into a state machine type. /// </summary> internal static BoundStatement Rewrite( BoundStatement body, MethodSymbol method, int methodOrdinal, VariableSlotAllocator slotAllocatorOpt, TypeCompilationState compilationState, DiagnosticBag diagnostics, out AsyncStateMachine stateMachineType) { if (!method.IsAsync) { stateMachineType = null; return(body); } // The CLR doesn't support adding fields to structs, so in order to enable EnC in an async method we need to generate a class. var typeKind = compilationState.Compilation.Options.EnableEditAndContinue ? TypeKind.Class : TypeKind.Struct; var bodyWithAwaitLifted = AwaitExpressionSpiller.Rewrite(body, method, compilationState, diagnostics); stateMachineType = new AsyncStateMachine(slotAllocatorOpt, compilationState, method, methodOrdinal, typeKind); compilationState.ModuleBuilderOpt.CompilationState.SetStateMachineType(method, stateMachineType); var rewriter = new AsyncRewriter(bodyWithAwaitLifted, method, methodOrdinal, stateMachineType, slotAllocatorOpt, compilationState, diagnostics); if (!rewriter._constructedSuccessfully) { return(body); } return(rewriter.Rewrite()); }
public AsyncStateMachine(VariableSlotAllocator variableAllocatorOpt, TypeCompilationState compilationState, MethodSymbol asyncMethod, int asyncMethodOrdinal, TypeKind typeKind) : base(variableAllocatorOpt, compilationState, asyncMethod, asyncMethodOrdinal) { // TODO: report use-site errors on these types _typeKind = typeKind; _interfaces = ImmutableArray.Create(asyncMethod.DeclaringCompilation.GetWellKnownType(WellKnownType.System_Runtime_CompilerServices_IAsyncStateMachine)); _constructor = new AsyncConstructor(this); }
public MethodToStateMachineRewriter( SyntheticBoundNodeFactory F, MethodSymbol originalMethod, FieldSymbol state, IReadOnlySet <Symbol> hoistedVariables, IReadOnlyDictionary <Symbol, CapturedSymbolReplacement> nonReusableLocalProxies, SynthesizedLocalOrdinalsDispenser synthesizedLocalOrdinals, ArrayBuilder <StateMachineStateDebugInfo> stateMachineStateDebugInfoBuilder, VariableSlotAllocator slotAllocatorOpt, int nextFreeHoistedLocalSlot, BindingDiagnosticBag diagnostics) : base(slotAllocatorOpt, F.CompilationState, diagnostics) { Debug.Assert(F != null); Debug.Assert(originalMethod != null); Debug.Assert(state != null); Debug.Assert(nonReusableLocalProxies != null); Debug.Assert(diagnostics != null); Debug.Assert(hoistedVariables != null); Debug.Assert(nextFreeHoistedLocalSlot >= 0); this.F = F; this.stateField = state; this.cachedState = F.SynthesizedLocal(F.SpecialType(SpecialType.System_Int32), syntax: F.Syntax, kind: SynthesizedLocalKind.StateMachineCachedState); this.OriginalMethod = originalMethod; _hoistedVariables = hoistedVariables; _synthesizedLocalOrdinals = synthesizedLocalOrdinals; _nextFreeHoistedLocalSlot = nextFreeHoistedLocalSlot; foreach (var proxy in nonReusableLocalProxies) { this.proxies.Add(proxy.Key, proxy.Value); } // create cache local for reference type "this" in Release var thisParameter = originalMethod.ThisParameter; CapturedSymbolReplacement thisProxy; if ((object)thisParameter != null && thisParameter.Type.IsReferenceType && proxies.TryGetValue(thisParameter, out thisProxy) && F.Compilation.Options.OptimizationLevel == OptimizationLevel.Release) { BoundExpression thisProxyReplacement = thisProxy.Replacement(F.Syntax, frameType => F.This()); this.cachedThis = F.SynthesizedLocal(thisProxyReplacement.Type, syntax: F.Syntax, kind: SynthesizedLocalKind.FrameCache); } _stateDebugInfoBuilder = stateMachineStateDebugInfoBuilder; // Use the first state number that is not used by any previous version of the state machine // for the first added state that doesn't match any states of the previous state machine. // Note the initial states of the previous and the current state machine are always the same. // Note the previous state machine might not have any non-initial states. _resumableStateAllocator = new ResumableStateMachineStateAllocator( slotAllocatorOpt, firstState: FirstIncreasingResumableState, increasing: true); }
protected MethodToClassRewriter(VariableSlotAllocator slotAllocatorOpt, TypeCompilationState compilationState, DiagnosticBag diagnostics) { Debug.Assert(compilationState != null); Debug.Assert(diagnostics != null); this.CompilationState = compilationState; this.Diagnostics = diagnostics; this.slotAllocatorOpt = slotAllocatorOpt; }
/// <summary> /// Rewrite an async method into a state machine type. /// </summary> internal static BoundStatement Rewrite( BoundStatement body, MethodSymbol method, int methodOrdinal, VariableSlotAllocator slotAllocatorOpt, TypeCompilationState compilationState, DiagnosticBag diagnostics, out AsyncStateMachine stateMachineType) { if (!method.IsAsync) { stateMachineType = null; return(body); } CSharpCompilation compilation = method.DeclaringCompilation; bool isAsyncEnumerableOrEnumerator = method.IsIAsyncEnumerableReturningAsync(compilation) || method.IsIAsyncEnumeratorReturningAsync(compilation); if (isAsyncEnumerableOrEnumerator && !method.IsIterator) { bool containsAwait = AwaitDetector.ContainsAwait(body); diagnostics.Add(containsAwait ? ErrorCode.ERR_PossibleAsyncIteratorWithoutYield : ErrorCode.ERR_PossibleAsyncIteratorWithoutYieldOrAwait, method.Locations[0], method.ReturnType); stateMachineType = null; return(body); } // The CLR doesn't support adding fields to structs, so in order to enable EnC in an async method we need to generate a class. // For async-iterators, we also need to generate a class. var typeKind = (compilationState.Compilation.Options.EnableEditAndContinue || method.IsIterator) ? TypeKind.Class : TypeKind.Struct; var bodyWithAwaitLifted = AwaitExpressionSpiller.Rewrite(body, method, compilationState, diagnostics); stateMachineType = new AsyncStateMachine(slotAllocatorOpt, compilationState, method, methodOrdinal, typeKind); compilationState.ModuleBuilderOpt.CompilationState.SetStateMachineType(method, stateMachineType); AsyncRewriter rewriter = isAsyncEnumerableOrEnumerator ? new AsyncIteratorRewriter(bodyWithAwaitLifted, method, methodOrdinal, stateMachineType, slotAllocatorOpt, compilationState, diagnostics) : new AsyncRewriter(bodyWithAwaitLifted, method, methodOrdinal, stateMachineType, slotAllocatorOpt, compilationState, diagnostics); if (!rewriter.VerifyPresenceOfRequiredAPIs()) { return(body); } try { return(rewriter.Rewrite()); } catch (SyntheticBoundNodeFactory.MissingPredefinedMember ex) { diagnostics.Add(ex.Diagnostic); return(new BoundBadStatement(body.Syntax, ImmutableArray.Create <BoundNode>(body), hasErrors: true)); } }
protected MethodToClassRewriter(VariableSlotAllocator slotAllocatorOpt, TypeCompilationState compilationState, DiagnosticBag diagnostics) { Debug.Assert(compilationState != null); Debug.Assert(diagnostics != null); this.CompilationState = compilationState; this.Diagnostics = diagnostics; this.slotAllocatorOpt = slotAllocatorOpt; this._placeholderMap = new Dictionary <BoundValuePlaceholderBase, BoundExpression>(); }
internal static BoundStatement ParseAndBindMethodBody(string program, bool lower, string typeName = DefaultTypeName, string methodName = DefaultMethodName) { var compilation = CreateCompilationWithMscorlib(program); var method = (MethodSymbol)compilation.GlobalNamespace.GetTypeMembers(typeName).Single().GetMembers(methodName).Single(); var diagnostics = DiagnosticBag.GetInstance(); try { // Provide an Emit.Module so that the lowering passes will be run var module = new PEAssemblyBuilder( (SourceAssemblySymbol)compilation.Assembly, EmitOptions.Default, OutputKind.ConsoleApplication, GetDefaultModulePropertiesForSerialization(), Enumerable.Empty <ResourceDescription>(), assemblySymbolMapper: null); TypeCompilationState compilationState = new TypeCompilationState(method.ContainingType, compilation, module); var block = MethodCompiler.BindMethodBody(method, compilationState, diagnostics); if ((block == null) || !lower) { return(block); } StateMachineTypeSymbol stateMachineTypeOpt; VariableSlotAllocator lazyVariableSlotAllocator = null; var lambdaDebugInfoBuilder = ArrayBuilder <LambdaDebugInfo> .GetInstance(); var closureDebugInfoBuilder = ArrayBuilder <ClosureDebugInfo> .GetInstance(); var body = MethodCompiler.LowerBodyOrInitializer( method: method, methodOrdinal: 0, body: block, previousSubmissionFields: null, compilationState: compilationState, diagnostics: diagnostics, lazyVariableSlotAllocator: ref lazyVariableSlotAllocator, lambdaDebugInfoBuilder: lambdaDebugInfoBuilder, closureDebugInfoBuilder: closureDebugInfoBuilder, stateMachineTypeOpt: out stateMachineTypeOpt); lambdaDebugInfoBuilder.Free(); closureDebugInfoBuilder.Free(); return(body); } finally { diagnostics.Free(); } }
private FieldSymbol _currentField; // stores the current/yielded value internal AsyncIteratorRewriter( BoundStatement body, MethodSymbol method, int methodOrdinal, AsyncStateMachine stateMachineType, VariableSlotAllocator slotAllocatorOpt, TypeCompilationState compilationState, DiagnosticBag diagnostics) : base(body, method, methodOrdinal, stateMachineType, slotAllocatorOpt, compilationState, diagnostics) { Debug.Assert(method.IteratorElementType != null); }
private AsyncRewriter( BoundStatement body, MethodSymbol method, int methodOrdinal, AsyncStateMachine stateMachineType, VariableSlotAllocator slotAllocatorOpt, TypeCompilationState compilationState, BindingDiagnosticBag diagnostics) : base(body, method, stateMachineType, slotAllocatorOpt, compilationState, diagnostics) { _constructedSuccessfully = AsyncMethodBuilderMemberCollection.TryCreate(F, method, this.stateMachineType.TypeMap, out _asyncMethodBuilderMemberCollection); _methodOrdinal = methodOrdinal; }
private static string MakeName(VariableSlotAllocator slotAllocatorOpt, TypeCompilationState compilationState, ClosureKind closureKind, MethodSymbol topLevelMethod, int topLevelMethodOrdinal, int lambdaOrdinal) { // TODO: slotAllocatorOpt?.GetPrevious() // Lambda method name must contain the declaring method ordinal to be unique unless the method is emitted into a closure class exclusive to the declaring method. // Lambdas that only close over "this" are emitted directly into the top-level method containing type. // Lambdas that don't close over anything (static) are emitted into a shared closure singleton. return(GeneratedNames.MakeLambdaMethodName( topLevelMethod.Name, (closureKind == ClosureKind.General) ? -1 : topLevelMethodOrdinal, compilationState.ModuleBuilderOpt.CurrentGenerationOrdinal, lambdaOrdinal)); }
internal static MethodBody GenerateMethodBody( PEModuleBuilder moduleBuilder, SourceRoutineSymbol routine, int methodOrdinal, //ImmutableArray<LambdaDebugInfo> lambdaDebugInfo, //ImmutableArray<ClosureDebugInfo> closureDebugInfo, //StateMachineTypeSymbol stateMachineTypeOpt, VariableSlotAllocator variableSlotAllocatorOpt, DiagnosticBag diagnostics, //ImportChain importChainOpt, bool emittingPdb) { return(GenerateMethodBody(moduleBuilder, routine, (builder) => { DiagnosticBag diagnosticsForThisMethod = DiagnosticBag.GetInstance(); var optimization = moduleBuilder.Compilation.Options.OptimizationLevel; var codeGen = new CodeGenerator(routine, builder, moduleBuilder, diagnosticsForThisMethod, optimization, emittingPdb); //if (diagnosticsForThisMethod.HasAnyErrors()) //{ // // we are done here. Since there were errors we should not emit anything. // return null; //} // We need to save additional debugging information for MoveNext of an async state machine. //var stateMachineMethod = method as SynthesizedStateMachineMethod; //bool isStateMachineMoveNextMethod = stateMachineMethod != null && method.Name == WellKnownMemberNames.MoveNextMethodName; //if (isStateMachineMoveNextMethod && stateMachineMethod.StateMachineType.KickoffMethod.IsAsync) //{ // int asyncCatchHandlerOffset; // ImmutableArray<int> asyncYieldPoints; // ImmutableArray<int> asyncResumePoints; // codeGen.Generate(out asyncCatchHandlerOffset, out asyncYieldPoints, out asyncResumePoints); // var kickoffMethod = stateMachineMethod.StateMachineType.KickoffMethod; // // The exception handler IL offset is used by the debugger to treat exceptions caught by the marked catch block as "user unhandled". // // This is important for async void because async void exceptions generally result in the process being terminated, // // but without anything useful on the call stack. Async Task methods on the other hand return exceptions as the result of the Task. // // So it is undesirable to consider these exceptions "user unhandled" since there may well be user code that is awaiting the task. // // This is a heuristic since it's possible that there is no user code awaiting the task. // asyncDebugInfo = new Cci.AsyncMethodBodyDebugInfo(kickoffMethod, kickoffMethod.ReturnsVoid ? asyncCatchHandlerOffset : -1, asyncYieldPoints, asyncResumePoints); //} //else { codeGen.Generate(); } }, variableSlotAllocatorOpt, diagnostics, emittingPdb)); }
private static string MakeName( VariableSlotAllocator slotAllocatorOpt, TypeCompilationState compilationState, MethodSymbol kickoffMethod, int kickoffMethodOrdinal ) { return(slotAllocatorOpt?.PreviousStateMachineTypeName ?? GeneratedNames.MakeStateMachineTypeName( kickoffMethod.Name, kickoffMethodOrdinal, compilationState.ModuleBuilderOpt.CurrentGenerationOrdinal )); }
public StateMachineTypeSymbol( VariableSlotAllocator slotAllocatorOpt, TypeCompilationState compilationState, MethodSymbol kickoffMethod, int kickoffMethodOrdinal ) : base( MakeName(slotAllocatorOpt, compilationState, kickoffMethod, kickoffMethodOrdinal), kickoffMethod ) { Debug.Assert(kickoffMethod != null); this.KickoffMethod = kickoffMethod; }
// new: public MethodToStateMachineRewriter( SyntheticBoundNodeFactory F, MethodSymbol originalMethod, FieldSymbol state, IReadOnlySet <Symbol> hoistedVariables, IReadOnlyDictionary <Symbol, CapturedSymbolReplacement> nonReusableLocalProxies, SynthesizedLocalOrdinalsDispenser synthesizedLocalOrdinals, VariableSlotAllocator slotAllocatorOpt, int nextFreeHoistedLocalSlot, DiagnosticBag diagnostics, bool useFinalizerBookkeeping) : base(slotAllocatorOpt, F.CompilationState, diagnostics) { Debug.Assert(F != null); Debug.Assert(originalMethod != null); Debug.Assert(state != null); Debug.Assert(nonReusableLocalProxies != null); Debug.Assert(diagnostics != null); Debug.Assert(hoistedVariables != null); Debug.Assert(nextFreeHoistedLocalSlot >= 0); this.F = F; this.stateField = state; this.cachedState = F.SynthesizedLocal(F.SpecialType(SpecialType.System_Int32), syntax: F.Syntax, kind: SynthesizedLocalKind.StateMachineCachedState); _useFinalizerBookkeeping = useFinalizerBookkeeping; _hasFinalizerState = useFinalizerBookkeeping; this.OriginalMethod = originalMethod; _hoistedVariables = hoistedVariables; _synthesizedLocalOrdinals = synthesizedLocalOrdinals; _nextFreeHoistedLocalSlot = nextFreeHoistedLocalSlot; foreach (var proxy in nonReusableLocalProxies) { this.proxies.Add(proxy.Key, proxy.Value); } // create cache local for reference type "this" in Release var thisParameter = originalMethod.ThisParameter; CapturedSymbolReplacement thisProxy; if ((object)thisParameter != null && thisParameter.Type.IsReferenceType && proxies.TryGetValue(thisParameter, out thisProxy) && F.Compilation.Options.OptimizationLevel == OptimizationLevel.Release) { BoundExpression thisProxyReplacement = thisProxy.Replacement(F.Syntax, frameType => F.This()); this.cachedThis = F.SynthesizedLocal(thisProxyReplacement.Type, syntax: F.Syntax, kind: SynthesizedLocalKind.FrameCache); } }
private IteratorRewriter( BoundStatement body, MethodSymbol method, bool isEnumerable, IteratorStateMachine stateMachineType, VariableSlotAllocator slotAllocatorOpt, TypeCompilationState compilationState, DiagnosticBag diagnostics) : base(body, method, stateMachineType, slotAllocatorOpt, compilationState, diagnostics) { // the element type may contain method type parameters, which are now alpha-renamed into type parameters of the generated class _elementType = stateMachineType.ElementType; _isEnumerable = isEnumerable; }
private Analysis( Scope scopeTree, PooledHashSet <MethodSymbol> methodsConvertedToDelegates, MethodSymbol topLevelMethod, int topLevelMethodOrdinal, VariableSlotAllocator slotAllocatorOpt, TypeCompilationState compilationState) { ScopeTree = scopeTree; MethodsConvertedToDelegates = methodsConvertedToDelegates; _topLevelMethod = topLevelMethod; _topLevelMethodOrdinal = topLevelMethodOrdinal; _slotAllocatorOpt = slotAllocatorOpt; _compilationState = compilationState; }
internal static BoundStatement Rewrite( BoundStatement body, MethodSymbol method, int methodOrdinal, ArrayBuilder <StateMachineStateDebugInfo> stateMachineStateDebugInfoBuilder, VariableSlotAllocator slotAllocatorOpt, TypeCompilationState compilationState, BindingDiagnosticBag diagnostics, out IteratorStateMachine stateMachineType) { TypeWithAnnotations elementType = method.IteratorElementTypeWithAnnotations; if (elementType.IsDefault || method.IsAsync) { stateMachineType = null; return(body); } // Figure out what kind of iterator we are generating. bool isEnumerable; switch (method.ReturnType.OriginalDefinition.SpecialType) { case SpecialType.System_Collections_IEnumerable: case SpecialType.System_Collections_Generic_IEnumerable_T: isEnumerable = true; break; case SpecialType.System_Collections_IEnumerator: case SpecialType.System_Collections_Generic_IEnumerator_T: isEnumerable = false; break; default: throw ExceptionUtilities.UnexpectedValue(method.ReturnType.OriginalDefinition.SpecialType); } stateMachineType = new IteratorStateMachine(slotAllocatorOpt, compilationState, method, methodOrdinal, isEnumerable, elementType); compilationState.ModuleBuilderOpt.CompilationState.SetStateMachineType(method, stateMachineType); var rewriter = new IteratorRewriter(body, method, isEnumerable, stateMachineType, stateMachineStateDebugInfoBuilder, slotAllocatorOpt, compilationState, diagnostics); if (!rewriter.VerifyPresenceOfRequiredAPIs()) { return(body); } return(rewriter.Rewrite()); }
public IteratorStateMachine(VariableSlotAllocator slotAllocatorOpt, TypeCompilationState compilationState, MethodSymbol iteratorMethod, int iteratorMethodOrdinal, bool isEnumerable, TypeSymbol elementType) : base(slotAllocatorOpt, compilationState, iteratorMethod, iteratorMethodOrdinal) { this.ElementType = TypeMap.SubstituteType(elementType).TypeSymbol; throw new NotImplementedException("TODO"); var interfaces = ArrayBuilder <NamedTypeSymbol> .GetInstance(); // TODO: Add proper arguments interfaces.Add(ContainingAssembly.GetSpecialType(SpecialType.core_Iterable_T_TIterator).Construct(ElementType)); _interfaces = interfaces.ToImmutableAndFree(); _constructor = new IteratorConstructor(this); }
private static string MakeName(VariableSlotAllocator slotAllocatorOpt, TypeCompilationState compilationState, int methodOrdinal, int scopeOrdinal, bool isStatic) { // TODO: slotAllocatorOpt?.GetPrevious() int generation = compilationState.ModuleBuilderOpt.CurrentGenerationOrdinal; if (isStatic) { // Display class is shared among static non-generic lambdas and also accross generations, method ordinal is -1. Debug.Assert(methodOrdinal >= -1); return(GeneratedNames.MakeStaticLambdaDisplayClassName(methodOrdinal, generation)); } Debug.Assert(methodOrdinal >= 0); return(GeneratedNames.MakeLambdaDisplayClassName(methodOrdinal, generation, scopeOrdinal)); }
internal LambdaFrame(VariableSlotAllocator slotAllocatorOpt, MethodSymbol topLevelMethod, MethodDebugId methodId, CSharpSyntaxNode scopeSyntaxOpt, int closureOrdinal) : base(MakeName(slotAllocatorOpt, scopeSyntaxOpt, methodId, closureOrdinal), topLevelMethod) { _topLevelMethod = topLevelMethod; _constructor = new LambdaFrameConstructor(this); this.ClosureOrdinal = closureOrdinal; // static lambdas technically have the class scope so the scope syntax is null if (scopeSyntaxOpt == null) { _staticConstructor = new SynthesizedStaticConstructor(this); var cacheVariableName = GeneratedNames.MakeCachedFrameInstanceFieldName(); _singletonCache = new SynthesizedLambdaCacheFieldSymbol(this, this, cacheVariableName, topLevelMethod, isReadOnly: true, isStatic: true); } AssertIsLambdaScopeSyntax(scopeSyntaxOpt); this.ScopeSyntaxOpt = scopeSyntaxOpt; }