Example #1
0
        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));
        }
Example #2
0
            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>();
        }
Example #4
0
        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);
        }
Example #5
0
            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;
 }
Example #7
0
        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);
        }
Example #8
0
        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;
        }
Example #10
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);
        }
Example #11
0
        /// <summary>
        /// Rewrite an async method into a state machine type.
        /// </summary>
        internal static BoundStatement Rewrite(
            BoundStatement body,
            MethodSymbol method,
            int methodOrdinal,
            VariableSlotAllocator slotAllocatorOpt,
            TypeCompilationState compilationState,
            DiagnosticBag diagnostics,
            out AsyncStateMachine stateMachineType)
        {
            if (!method.IsAsync)
            {
                stateMachineType = null;
                return(body);
            }

            // The CLR doesn't support adding fields to structs, so in order to enable EnC in an async method we need to generate a class.
            var typeKind = compilationState.Compilation.Options.EnableEditAndContinue ? TypeKind.Class : TypeKind.Struct;

            var bodyWithAwaitLifted = AwaitExpressionSpiller.Rewrite(body, method, compilationState, diagnostics);

            stateMachineType = new AsyncStateMachine(slotAllocatorOpt, compilationState, method, methodOrdinal, typeKind);
            compilationState.ModuleBuilderOpt.CompilationState.SetStateMachineType(method, stateMachineType);
            var rewriter = new AsyncRewriter(bodyWithAwaitLifted, method, methodOrdinal, stateMachineType, slotAllocatorOpt, compilationState, diagnostics);

            if (!rewriter._constructedSuccessfully)
            {
                return(body);
            }

            return(rewriter.Rewrite());
        }
Example #12
0
 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);
        }
Example #14
0
        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;
        }
Example #15
0
        /// <summary>
        /// Rewrite an async method into a state machine type.
        /// </summary>
        internal static BoundStatement Rewrite(
            BoundStatement body,
            MethodSymbol method,
            int methodOrdinal,
            VariableSlotAllocator slotAllocatorOpt,
            TypeCompilationState compilationState,
            DiagnosticBag diagnostics,
            out AsyncStateMachine stateMachineType)
        {
            if (!method.IsAsync)
            {
                stateMachineType = null;
                return(body);
            }

            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));
            }
        }
Example #16
0
        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();
            }
        }
Example #18
0
            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);
            }
Example #19
0
 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;
 }
Example #20
0
        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));
        }
Example #21
0
        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));
        }
Example #22
0
 private static string MakeName(
     VariableSlotAllocator slotAllocatorOpt,
     TypeCompilationState compilationState,
     MethodSymbol kickoffMethod,
     int kickoffMethodOrdinal
     )
 {
     return(slotAllocatorOpt?.PreviousStateMachineTypeName
            ?? GeneratedNames.MakeStateMachineTypeName(
                kickoffMethod.Name,
                kickoffMethodOrdinal,
                compilationState.ModuleBuilderOpt.CurrentGenerationOrdinal
                ));
 }
Example #23
0
 public StateMachineTypeSymbol(
     VariableSlotAllocator slotAllocatorOpt,
     TypeCompilationState compilationState,
     MethodSymbol kickoffMethod,
     int kickoffMethodOrdinal
     )
     : base(
         MakeName(slotAllocatorOpt, compilationState, kickoffMethod, kickoffMethodOrdinal),
         kickoffMethod
         )
 {
     Debug.Assert(kickoffMethod != null);
     this.KickoffMethod = kickoffMethod;
 }
Example #24
0
        // 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);
            }
        }
Example #25
0
        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;
 }
Example #27
0
        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());
        }
Example #28
0
        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);
        }
Example #29
0
        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));
        }
Example #30
0
        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;
        }