public AddedOrChangedMethodInfo(
            MethodDebugId methodId,
            ImmutableArray<EncLocalInfo> locals, 
            ImmutableArray<LambdaDebugInfo> lambdaDebugInfo,
            ImmutableArray<ClosureDebugInfo> closureDebugInfo,
            string stateMachineTypeNameOpt,
            ImmutableArray<EncHoistedLocalInfo> stateMachineHoistedLocalSlotsOpt,
            ImmutableArray<Cci.ITypeReference> stateMachineAwaiterSlotsOpt)
        {
            // method can only be added/changed during EnC, thus generation can't be 0.
            Debug.Assert(methodId.Generation >= 1);

            // each state machine has to have awaiters:
            Debug.Assert(stateMachineAwaiterSlotsOpt.IsDefault == (stateMachineTypeNameOpt == null));

            // a state machine might not have hoisted variables:
            Debug.Assert(stateMachineHoistedLocalSlotsOpt.IsDefault || (stateMachineTypeNameOpt != null));

            this.MethodId = methodId;
            this.Locals = locals;
            this.LambdaDebugInfo = lambdaDebugInfo;
            this.ClosureDebugInfo = closureDebugInfo;
            this.StateMachineTypeNameOpt = stateMachineTypeNameOpt;
            this.StateMachineHoistedLocalSlotsOpt = stateMachineHoistedLocalSlotsOpt;
            this.StateMachineAwaiterSlotsOpt = stateMachineAwaiterSlotsOpt;
        }
Example #2
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);
        }
        public AddedOrChangedMethodInfo(
            MethodDebugId methodId,
            ImmutableArray <EncLocalInfo> locals,
            ImmutableArray <LambdaDebugInfo> lambdaDebugInfo,
            ImmutableArray <ClosureDebugInfo> closureDebugInfo,
            string stateMachineTypeNameOpt,
            ImmutableArray <EncHoistedLocalInfo> stateMachineHoistedLocalSlotsOpt,
            ImmutableArray <Cci.ITypeReference> stateMachineAwaiterSlotsOpt)
        {
            // method can only be added/changed during EnC, thus generation can't be 0.
            Debug.Assert(methodId.Generation >= 1);

            // each state machine has to have awaiters:
            Debug.Assert(stateMachineAwaiterSlotsOpt.IsDefault == (stateMachineTypeNameOpt == null));

            // a state machine might not have hoisted variables:
            Debug.Assert(stateMachineHoistedLocalSlotsOpt.IsDefault || (stateMachineTypeNameOpt != null));

            this.MethodId                         = methodId;
            this.Locals                           = locals;
            this.LambdaDebugInfo                  = lambdaDebugInfo;
            this.ClosureDebugInfo                 = closureDebugInfo;
            this.StateMachineTypeNameOpt          = stateMachineTypeNameOpt;
            this.StateMachineHoistedLocalSlotsOpt = stateMachineHoistedLocalSlotsOpt;
            this.StateMachineAwaiterSlotsOpt      = stateMachineAwaiterSlotsOpt;
        }
 private static string MakeName(string topLevelMethodName, MethodDebugId topLevelMethodId, ClosureKind closureKind, int lambdaOrdinal)
 {
     // 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(
         topLevelMethodName,
         (closureKind == ClosureKind.General) ? -1 : topLevelMethodId.Ordinal,
         topLevelMethodId.Generation,
         lambdaOrdinal);
 }
Example #5
0
 private static string MakeName(string topLevelMethodName, MethodDebugId topLevelMethodId, ClosureKind closureKind, int lambdaOrdinal)
 {
     // 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(
                topLevelMethodName,
                (closureKind == ClosureKind.General) ? -1 : topLevelMethodId.Ordinal,
                topLevelMethodId.Generation,
                lambdaOrdinal));
 }
        private readonly IReadOnlyDictionary <int, int> _closureMapOpt;                     // SyntaxOffset -> Ordinal

        public EncVariableSlotAllocator(
            SymbolMatcher symbolMap,
            Func <SyntaxNode, SyntaxNode> syntaxMapOpt,
            IMethodSymbolInternal previousMethod,
            MethodDebugId previousMethodId,
            ImmutableArray <EncLocalInfo> previousLocals,
            IReadOnlyDictionary <int, KeyValuePair <int, int> > lambdaMapOpt,
            IReadOnlyDictionary <int, int> closureMapOpt,
            string stateMachineTypeNameOpt,
            int hoistedLocalSlotCount,
            IReadOnlyDictionary <EncHoistedLocalInfo, int> hoistedLocalSlotsOpt,
            int awaiterCount,
            IReadOnlyDictionary <Cci.ITypeReference, int> awaiterMapOpt)
        {
            Debug.Assert(symbolMap != null);
            Debug.Assert(previousMethod != null);
            Debug.Assert(!previousLocals.IsDefault);

            _symbolMap               = symbolMap;
            _syntaxMapOpt            = syntaxMapOpt;
            _previousLocals          = previousLocals;
            _previousMethod          = previousMethod;
            _previousMethodId        = previousMethodId;
            _hoistedLocalSlotsOpt    = hoistedLocalSlotsOpt;
            _hoistedLocalSlotCount   = hoistedLocalSlotCount;
            _stateMachineTypeNameOpt = stateMachineTypeNameOpt;
            _awaiterCount            = awaiterCount;
            _awaiterMapOpt           = awaiterMapOpt;
            _lambdaMapOpt            = lambdaMapOpt;
            _closureMapOpt           = closureMapOpt;

            // Create a map from local info to slot.
            var previousLocalInfoToSlot = new Dictionary <EncLocalInfo, int>();

            for (int slot = 0; slot < previousLocals.Length; slot++)
            {
                var localInfo = previousLocals[slot];
                Debug.Assert(!localInfo.IsDefault);
                if (localInfo.IsUnused)
                {
                    // Unrecognized or deleted local.
                    continue;
                }

                previousLocalInfoToSlot.Add(localInfo, slot);
            }

            _previousLocalSlots = previousLocalInfoToSlot;
        }
        private readonly IReadOnlyDictionary<int, int> _closureMapOpt; // SyntaxOffset -> Ordinal

        public EncVariableSlotAllocator(
            SymbolMatcher symbolMap,
            Func<SyntaxNode, SyntaxNode> syntaxMapOpt,
            IMethodSymbolInternal previousMethod,
            MethodDebugId previousMethodId,
            ImmutableArray<EncLocalInfo> previousLocals,
            IReadOnlyDictionary<int, KeyValuePair<int, int>> lambdaMapOpt,
            IReadOnlyDictionary<int, int> closureMapOpt,
            string stateMachineTypeNameOpt,
            int hoistedLocalSlotCount,
            IReadOnlyDictionary<EncHoistedLocalInfo, int> hoistedLocalSlotsOpt,
            int awaiterCount,
            IReadOnlyDictionary<Cci.ITypeReference, int> awaiterMapOpt)
        {
            Debug.Assert(symbolMap != null);
            Debug.Assert(previousMethod != null);
            Debug.Assert(!previousLocals.IsDefault);

            _symbolMap = symbolMap;
            _syntaxMapOpt = syntaxMapOpt;
            _previousLocals = previousLocals;
            _previousMethod = previousMethod;
            _previousMethodId = previousMethodId;
            _hoistedLocalSlotsOpt = hoistedLocalSlotsOpt;
            _hoistedLocalSlotCount = hoistedLocalSlotCount;
            _stateMachineTypeNameOpt = stateMachineTypeNameOpt;
            _awaiterCount = awaiterCount;
            _awaiterMapOpt = awaiterMapOpt;
            _lambdaMapOpt = lambdaMapOpt;
            _closureMapOpt = closureMapOpt;

            // Create a map from local info to slot.
            var previousLocalInfoToSlot = new Dictionary<EncLocalInfo, int>();
            for (int slot = 0; slot < previousLocals.Length; slot++)
            {
                var localInfo = previousLocals[slot];
                Debug.Assert(!localInfo.IsDefault);
                if (localInfo.IsUnused)
                {
                    // Unrecognized or deleted local.
                    continue;
                }

                previousLocalInfoToSlot.Add(localInfo, slot);
            }

            _previousLocalSlots = previousLocalInfoToSlot;
        }
Example #8
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;
        }
        internal SynthesizedLambdaMethod(
            NamedTypeSymbol containingType,
            ClosureKind closureKind,
            MethodSymbol topLevelMethod,
            MethodDebugId topLevelMethodId,
            BoundLambda lambdaNode,
            int lambdaOrdinal)
            : base(containingType,
                   lambdaNode.Symbol,
                   null,
                   lambdaNode.SyntaxTree.GetReference(lambdaNode.Body.Syntax),
                   lambdaNode.Syntax.GetLocation(),
                   MakeName(topLevelMethod.Name, topLevelMethodId, closureKind, lambdaOrdinal),
                   (closureKind == ClosureKind.ThisOnly ? DeclarationModifiers.Private : DeclarationModifiers.Internal)
                       | (lambdaNode.Symbol.IsAsync ? DeclarationModifiers.Async : 0))
        {
            _topLevelMethod = topLevelMethod;

            TypeMap typeMap;
            ImmutableArray<TypeParameterSymbol> typeParameters;
            LambdaFrame lambdaFrame;

            if (!topLevelMethod.IsGenericMethod)
            {
                typeMap = TypeMap.Empty;
                typeParameters = ImmutableArray<TypeParameterSymbol>.Empty;
            }
            else if ((object)(lambdaFrame = this.ContainingType as LambdaFrame) != null)
            {
                typeMap = lambdaFrame.TypeMap;
                typeParameters = ImmutableArray<TypeParameterSymbol>.Empty;
            }
            else
            {
                typeMap = TypeMap.Empty.WithAlphaRename(topLevelMethod, this, out typeParameters);
            }

            AssignTypeMapAndTypeParameters(typeMap, typeParameters);
        }
Example #10
0
        internal SynthesizedLambdaMethod(
            NamedTypeSymbol containingType,
            ClosureKind closureKind,
            MethodSymbol topLevelMethod,
            MethodDebugId topLevelMethodId,
            BoundLambda lambdaNode,
            int lambdaOrdinal)
            : base(containingType,
                   lambdaNode.Symbol,
                   null,
                   lambdaNode.SyntaxTree.GetReference(lambdaNode.Body.Syntax),
                   lambdaNode.Syntax.GetLocation(),
                   MakeName(topLevelMethod.Name, topLevelMethodId, closureKind, lambdaOrdinal),
                   (closureKind == ClosureKind.ThisOnly ? DeclarationModifiers.Private : DeclarationModifiers.Internal)
                   | (lambdaNode.Symbol.IsAsync ? DeclarationModifiers.Async : 0))
        {
            _topLevelMethod = topLevelMethod;

            TypeMap typeMap;
            ImmutableArray <TypeParameterSymbol> typeParameters;
            LambdaFrame lambdaFrame;

            if (!topLevelMethod.IsGenericMethod)
            {
                typeMap        = TypeMap.Empty;
                typeParameters = ImmutableArray <TypeParameterSymbol> .Empty;
            }
            else if ((object)(lambdaFrame = this.ContainingType as LambdaFrame) != null)
            {
                typeMap        = lambdaFrame.TypeMap;
                typeParameters = ImmutableArray <TypeParameterSymbol> .Empty;
            }
            else
            {
                typeMap = TypeMap.Empty.WithAlphaRename(topLevelMethod, this, out typeParameters);
            }

            AssignTypeMapAndTypeParameters(typeMap, typeParameters);
        }
Example #11
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 #12
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;
        }