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